コード例 #1
0
ファイル: test_models_course.py プロジェクト: forkkit/richie
    def test_models_course_get_main_organization(self):
        """
        The `get_main_organization` method should return the first organization linked to a
        course via plugins, respecting publication status.
        """
        # The 2 first organizations are grouped in one variable name and will be linked to the
        # course in the following, the third category will not be linked so we can check that
        # only the organizations linked to the course are retrieved (its name starts with `_`
        # because it is not used and only here for unpacking purposes)
        *draft_organizations, _other_draft = OrganizationFactory.create_batch(
            3)
        *published_organizations, _other_public = OrganizationFactory.create_batch(
            3, should_publish=True)

        # Shuffle all organizations to make sure their order in the placeholder is what
        # determines which one is the main organization
        all_organizations = draft_organizations + published_organizations
        random.shuffle(all_organizations)

        course = CourseFactory(fill_organizations=all_organizations,
                               should_publish=True)

        self.assertEqual(course.get_main_organization(), all_organizations[0])
        self.assertEqual(
            course.public_extension.get_main_organization(),
            # Find the first published organization in this list of organizations
            next(o for o in all_organizations if o in published_organizations),
        )
コード例 #2
0
ファイル: test_models_course.py プロジェクト: nusiloot/richie
    def test_models_course_get_organizations(self):
        """
        The `get_organizations` method should return all organizations linked to a course and
        should respect publication status.
        """
        # The 2 first organizations are grouped in one variable name and will be linked to the
        # course in the following, the third category will not be linked so we can check that
        # only the organizations linked to the course are retrieved (its name starts with `_`
        # because it is not used and only here for unpacking purposes)
        *draft_organizations, _other_draft = OrganizationFactory.create_batch(3)
        *published_organizations, _other_public = OrganizationFactory.create_batch(
            3, should_publish=True
        )
        course = CourseFactory(
            fill_organizations=draft_organizations + published_organizations,
            should_publish=True,
        )

        self.assertEqual(
            list(course.get_organizations()),
            draft_organizations + published_organizations,
        )
        self.assertEqual(
            list(course.public_extension.get_organizations()), published_organizations
        )
コード例 #3
0
ファイル: test_models_course.py プロジェクト: phuoclhb/richie
    def test_models_course_get_organizations_other_placeholders(self):
        """
        The `get_organizations` method should return all organizations linked to a course via a
        plugin on whichever placeholder.
        """
        organization1, organization2 = OrganizationFactory.create_batch(2)

        course = CourseFactory(should_publish=True)
        placeholder1 = course.extended_object.placeholders.get(
            slot="course_description")
        placeholder2 = course.extended_object.placeholders.get(
            slot="course_format")

        add_plugin(
            language="en",
            placeholder=placeholder1,
            plugin_type="OrganizationPlugin",
            page=organization1.extended_object,
        )
        add_plugin(
            language="en",
            placeholder=placeholder2,
            plugin_type="OrganizationPlugin",
            page=organization2.extended_object,
        )

        self.assertEqual(list(course.get_organizations()),
                         [organization1, organization2])
コード例 #4
0
    def test_course_organizations_copied_when_publishing(self):
        """
        When publishing a course, the links to draft organizations on the draft version of the
        course should be copied (clear then add) to the published version.
        Links to published organizations should not be copied as they are redundant and not
        up-to-date.
        """
        # Create draft organizations
        organization1, organization2 = OrganizationFactory.create_batch(2)

        # Create a draft course
        draft_course = CourseFactory(
            with_organizations=[organization1, organization2])

        # Publish organization1
        organization1.extended_object.publish("en")
        organization1.refresh_from_db()

        # The course should see all organizations and propose a custom filter to easily access
        # the draft versions
        self.assertEqual(
            set(draft_course.organizations.all()),
            {
                organization1,
                organization1.public_extension,
                organization2,
                draft_course.organization_main,
            },
        )
        self.assertEqual(
            set(draft_course.organizations.drafts()),
            {organization1, organization2, draft_course.organization_main},
        )

        # Publish the course and check that the organizations are copied
        draft_course.extended_object.publish("en")
        published_course = Course.objects.get(
            extended_object__publisher_is_draft=False)
        self.assertEqual(
            set(published_course.organizations.all()),
            {organization1, organization2, draft_course.organization_main},
        )
        # When publishing, the organizations that are obsolete should be cleared
        draft_course.organizations.remove(organization2)
        self.assertEqual(
            set(published_course.organizations.all()),
            {organization1, organization2, draft_course.organization_main},
        )
        # Organizations on the published course are only cleared after publishing the draft page
        draft_course.extended_object.publish("en")
        self.assertEqual(
            set(published_course.organizations.all()),
            {organization1, draft_course.organization_main},
        )
コード例 #5
0
ファイル: test_models_course.py プロジェクト: lunika/richie
    def test_models_course_organizations_copied_when_publishing(self):
        """
        When publishing a course, the links to draft organizations on the draft version of the
        course should be copied (clear then add) to set equivalent links between the corresponding
        published course and published organizations.
        """
        # Create organizations: 2 published and 1 draft
        organization1, organization2 = OrganizationFactory.create_batch(
            2, should_publish=True)
        organization3 = OrganizationFactory()

        # Create a draft course
        draft_course = CourseFactory(
            organization_main=organization1,
            with_organizations=[organization2, organization3],
        )

        # The course should see all organizations as the main organization should be added to
        # the organizatiions many-to-many relation
        self.assertEqual(
            set(draft_course.organizations.all()),
            {organization1, organization2, organization3},
        )

        # Publish the course and check that the organizations are copied
        draft_course.extended_object.publish("en")
        published_course = Course.objects.get(
            extended_object__publisher_is_draft=False)
        self.assertEqual(
            set(published_course.organizations.all()),
            {
                organization1.public_extension,
                organization2.public_extension,
                draft_course.organization_main.public_extension,
            },
        )
        # A published organization should see the published course
        self.assertEqual(organization1.public_extension.courses.first(),
                         published_course)

        # The organizations that are removed from the draft course should only be cleared from the
        # published course upon publishing
        draft_course.organizations.remove(organization1)
        self.assertEqual(
            set(published_course.organizations.all()),
            {organization1.public_extension, organization2.public_extension},
        )
        draft_course.extended_object.publish("en")
        self.assertEqual(set(published_course.organizations.all()),
                         {organization2.public_extension})
        # The published organization that was removed should not see the published course any more
        self.assertIsNone(organization1.public_extension.courses.first())
コード例 #6
0
    def test_context_processors_get_organizations_code(self):
        """
        If an organization is linked to the page or there are organization plugins on the page,
        marketing context should contains the code of these organizations
        """
        organizations = OrganizationFactory.create_batch(2,
                                                         should_publish=True)
        course = CourseFactory(should_publish=True,
                               fill_organizations=organizations)

        response = self.client.get(course.extended_object.get_public_url(),
                                   follow=True)
        organizations_codes = Organization.get_organizations_codes(
            course.extended_object, "fr")
        pattern = fr'"organizations_codes": "{" | ".join(list(organizations_codes))}"'

        self.assertEqual(response.status_code, 200)
        self.assertIsNotNone(re.search(pattern, str(response.content)))
コード例 #7
0
    def test_context_processors_queries_are_cached(self):
        """
        Once the page is cached, no db queries should be made again
        """
        organizations = OrganizationFactory.create_batch(2,
                                                         should_publish=True,
                                                         page_languages=["fr"])
        course = CourseFactory(should_publish=True,
                               fill_organizations=organizations,
                               page_languages=["fr"])
        page = course.extended_object

        # Get the page a first time to cache it
        self.client.get(page.get_public_url())

        # Check that db queries are well cached
        # The one remaining is related to django-cms
        with self.assertNumQueries(1):
            self.client.get(page.get_public_url())
コード例 #8
0
    def test_course_change_view_post(self):
        """
        Validate that the course can be updated via the admin.
        In particular, make sure that when a course is updated from the admin, the main
        organization is automatically added to the many-to-many field "organizations".
        See http://stackoverflow.com/a/1925784/469575 for details on the issue.
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        # Create a course, some organizations and some subjects
        organization1, organization2, organization3 = OrganizationFactory.create_batch(
            3
        )
        subject1, subject2 = SubjectFactory.create_batch(2)
        course = CourseFactory(
            with_organizations=[organization1], with_subjects=[subject1]
        )
        self.assertEqual(
            set(course.organizations.all()), {organization1, course.organization_main}
        )
        self.assertEqual(set(course.subjects.all()), {subject1})

        # Get the admin change view
        url = reverse("admin:courses_course_change", args=[course.id])
        data = {
            "active_session": "xyz",
            "organization_main": organization2.id,
            "organizations": [organization3.id],
            "subjects": [subject2.id],
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 302)

        # Check that the course was updated as expected
        course.refresh_from_db()
        self.assertEqual(course.active_session, "xyz")
        self.assertEqual(course.organization_main, organization2)
        self.assertEqual(set(course.subjects.all()), {subject2})
        # Check that the main organization was added and the old organization cleared
        self.assertEqual(
            set(course.organizations.all()), {organization2, organization3}
        )
コード例 #9
0
    def test_course_organization_main_always_included_in_organizations(self):
        """
        The main organization should always be in the organizations linked via many-to-many
        """
        organization1, organization2 = OrganizationFactory.create_batch(2)
        course = CourseFactory(organization_main=organization1)
        self.assertEqual(list(course.organizations.all()), [organization1])

        # Now set the second organization as the main
        course.organization_main = organization2
        course.save()
        self.assertEqual(course.organization_main, organization2)
        self.assertEqual(list(course.organizations.all()),
                         [organization1, organization2])

        # Setting an organization that is already included as many-to-many should not fail
        course.organization_main = organization1
        course.save()
        self.assertEqual(course.organization_main, organization1)
        self.assertEqual(list(course.organizations.all()),
                         [organization1, organization2])
コード例 #10
0
    def test_templates_course_detail_organization_main_logo(self):
        """The main organization logo should be present on the page with a link."""
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        organizations = OrganizationFactory.create_batch(
            2, fill_logo=True, should_publish=True
        )
        course = CourseFactory(fill_organizations=organizations)

        response = self.client.get(course.extended_object.get_absolute_url())

        self.assertEqual(response.status_code, 200)
        pattern = (
            r'<a href="{url:s}" title="{title:s}" class="course-detail__aside__main-org-logo">'
            r'<img src="/media/filer_public_thumbnails/filer_public/.*logo\.jpg__200x113'
        ).format(
            url=organizations[0].extended_object.get_absolute_url(),
            title=organizations[0].extended_object.get_title(),
        )
        self.assertIsNotNone(re.search(pattern, str(response.content)))
コード例 #11
0
    def test_models_category_get_organizations(self):
        """
        It should be possible to retrieve the list of related organizations on the category
        instance. The number of queries should be minimal.
        """
        category = CategoryFactory(should_publish=True)
        organizations = OrganizationFactory.create_batch(
            2,
            page_title="my title",
            fill_categories=[category],
            should_publish=True)
        retrieved_organizations = category.get_organizations()

        with self.assertNumQueries(2):
            self.assertEqual(set(retrieved_organizations), set(organizations))

        with self.assertNumQueries(0):
            for organization in retrieved_organizations:
                self.assertEqual(
                    organization.extended_object.prefetched_titles[0].title,
                    "my title")
コード例 #12
0
    def test_models_category_get_organizations_ordering(self):
        """The related organizations should be sorted by their position in the pages tree."""
        category = CategoryFactory(should_publish=True)
        organization1, organization2, organization3 = OrganizationFactory.create_batch(
            3, fill_categories=[category], should_publish=True)
        self.assertEqual(
            list(category.get_organizations()),
            [organization1, organization2, organization3],
        )

        # Move pages in the tree and check that they are returned in the new order
        organization3.extended_object.move_page(
            organization1.extended_object.node, position="left")
        self.assertEqual(
            list(category.get_organizations()),
            [organization3, organization1, organization2],
        )

        organization1.extended_object.move_page(
            organization3.extended_object.node, position="left")
        self.assertEqual(
            list(category.get_organizations()),
            [organization1, organization3, organization2],
        )
コード例 #13
0
    def test_course_cms_published_content(self):
        """
        Validate that the important elements are displayed on a published course page
        """
        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            organization_main=organizations[0],
            title="Very interesting course",
            with_organizations=organizations,
            with_subjects=subjects,
        )
        page = course.extended_object

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Publish and ensure content is correct
        page.publish("en")
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)

        self.assertContains(response,
                            "<title>Very interesting course</title>",
                            html=True)
        self.assertContains(
            response,
            '<h1 class="course-detail__title">Very interesting course</h1>',
            html=True,
        )
        self.assertContains(
            response,
            '<div class="course-detail__aside__active-session">{:s}</div>'.
            format(course.active_session),
            html=True,
        )

        # Only published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<li class="course-detail__content__subjects__item">{:s}</li>'.
                format(subject.extended_object.get_title()),
                html=True,
            )
        for subject in subjects[-2:]:
            self.assertNotContains(response,
                                   subject.extended_object.get_title())

        # organization 1 is marked as main organization
        self.assertContains(
            response,
            '<li class="{element:s} {element:s}--main">{title:s}</li>'.format(
                element="course-detail__content__organizations__item",
                title=organizations[0].extended_object.get_title(),
            ),
            html=True,
        )

        # organization 2 is the only "common" org in listing
        self.assertContains(
            response,
            '<li class="course-detail__content__organizations__item">{:s}</li>'
            .format(organizations[1].extended_object.get_title()),
            html=True,
        )

        # Draft organization should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(response,
                                   organization.extended_object.get_title(),
                                   html=True)
コード例 #14
0
    def test_models_organization_get_persons_language_fallback_published(self):
        """
        Validate that the reverse persons lookup works as expected with language fallback
        on a published page.
        """
        organization1, organization2, organization3 = OrganizationFactory.create_batch(
            3, should_publish=True)
        public_organization1 = organization1.public_extension
        public_organization2 = organization2.public_extension
        public_organization3 = organization3.public_extension

        person, person_unpublished = PersonFactory.create_batch(
            2, page_languages=["en", "fr", "de"], should_publish=True)

        public_person = person.public_extension

        public_person_unpublished = person_unpublished.public_extension
        person_unpublished.extended_object.unpublish("en")
        person_unpublished.extended_object.unpublish("fr")
        person_unpublished.extended_object.unpublish("de")

        placeholder = public_person.extended_object.placeholders.get(
            slot="organizations")
        placeholder_unpublished = (
            public_person_unpublished.extended_object.placeholders.get(
                slot="organizations"))
        # Reverse plugin lookups should fallback up to the second priority language
        add_plugin(
            language="de",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization1.extended_object},
        )
        add_plugin(
            language="de",
            placeholder=placeholder_unpublished,
            plugin_type="OrganizationPlugin",
            **{"page": organization1.extended_object},
        )

        with translation.override("en"):
            self.assertEqual(list(public_organization1.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()), [])

        with translation.override("fr"):
            self.assertEqual(list(public_organization1.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()), [])

        with translation.override("de"):
            self.assertEqual(list(public_organization1.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()), [])

        # Reverse plugin lookups should fallback to the first priority language if available
        # and ignore the second priority language unless it is the current language
        add_plugin(
            language="fr",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization2.extended_object},
        )
        add_plugin(
            language="fr",
            placeholder=placeholder_unpublished,
            plugin_type="OrganizationPlugin",
            **{"page": organization2.extended_object},
        )
        with translation.override("en"):
            self.assertEqual(list(public_organization1.get_persons()), [])
            self.assertEqual(list(public_organization2.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization3.get_persons()), [])

        with translation.override("fr"):
            self.assertEqual(list(public_organization1.get_persons()), [])
            self.assertEqual(list(public_organization2.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization3.get_persons()), [])

        with translation.override("de"):
            self.assertEqual(list(public_organization1.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()), [])

        # Reverse plugin lookups should stick to the current language if available and
        # ignore plugins on fallback languages
        add_plugin(
            language="en",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization3.extended_object},
        )
        add_plugin(
            language="en",
            placeholder=placeholder_unpublished,
            plugin_type="OrganizationPlugin",
            **{"page": organization3.extended_object},
        )
        with translation.override("en"):
            self.assertEqual(list(public_organization1.get_persons()), [])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()),
                             [public_person])

        with translation.override("fr"):
            self.assertEqual(list(public_organization1.get_persons()), [])
            self.assertEqual(list(public_organization2.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization3.get_persons()), [])

        with translation.override("de"):
            self.assertEqual(list(public_organization1.get_persons()),
                             [public_person])
            self.assertEqual(list(public_organization2.get_persons()), [])
            self.assertEqual(list(public_organization3.get_persons()), [])
コード例 #15
0
    def test_course_cms_draft_content(self):
        """
        A staff user should see a draft course including its draft elements with
        an annotation
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            organization_main=organizations[0],
            title="Very interesting course",
            with_organizations=organizations,
            with_subjects=subjects,
        )
        page = course.extended_object

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should be visible as draft to the staff user
        url = page.get_absolute_url()
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)

        self.assertContains(response,
                            "<title>Very interesting course</title>",
                            html=True)
        self.assertContains(
            response,
            '<h1 class="course-detail__title">Very interesting course</h1>',
            html=True,
        )
        self.assertContains(
            response,
            '<div class="course-detail__aside__active-session">{:s}</div>'.
            format(course.active_session),
            html=True,
        )

        # organization 1 is marked as main and not duplicated
        self.assertContains(
            response,
            '<li class="{element:s} {element:s}--main">{title:s}</li>'.format(
                element="course-detail__content__organizations__item",
                title=organizations[0].extended_object.get_title(),
            ),
            html=True,
        )
        self.assertNotContains(
            response,
            ('<li class="course-detail__content__organizations__item">{:s}</li>'
             ).format(organizations[0].extended_object.get_title()),
            html=True,
        )
        # organization 2 is not marked as a draft since it has been published
        self.assertContains(
            response,
            '<li class="course-detail__content__organizations__item">{:s}</li>'
            .format(organizations[1].extended_object.get_title()),
            html=True,
        )
        # Draft organizations should be present on the page with an annotation for styling
        for organization in organizations[:2]:
            self.assertNotContains(
                response,
                '<li class="{element:s} {element:s}--draft">{title:s}</li>'.
                format(
                    element="course - detail__content__organizations__item",
                    title=organization.extended_object.get_title(),
                ),
                html=True,
            )

        # The published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<li class="course-detail__content__subjects__item">{:s}</li>'.
                format(subject.extended_object.get_title()),
                html=True,
            )
        # Draft subjects should also be present on the page with an annotation for styling
        for subject in subjects[-2:]:
            self.assertContains(
                response,
                '<li class="{element:s} {element:s}--draft">{title:s}</li>'.
                format(
                    element="course-detail__content__subjects__item",
                    title=subject.extended_object.get_title(),
                ),
                html=True,
            )
コード例 #16
0
    def test_templates_course_run_detail_cms_published_content(self):
        """
        Validate that the important elements are displayed on a published course run page
        """
        categories = CategoryFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_categories=categories,
            should_publish=True,
        )
        course_run = CourseRunFactory(
            page_title="first session",
            page_parent=course.extended_object,
            resource_link="https://www.example.com/enroll",
            enrollment_start=datetime(2018, 10, 21, tzinfo=pytz.utc),
            enrollment_end=datetime(2019, 1, 18, tzinfo=pytz.utc),
            start=datetime(2018, 12, 10, tzinfo=pytz.utc),
            end=datetime(2019, 2, 14, tzinfo=pytz.utc),
            languages=["en", "fr"],
        )
        page = course_run.extended_object

        # Publish only 2 out of 4 categories and 2 out of 4 organizations
        categories[0].extended_object.publish("en")
        categories[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        categories[2].extended_object.publish("en")
        categories[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Now publish the page and check its content
        page.publish("en")
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response,
            "<title>First session - Very interesting course</title>",
            html=True,
        )
        self.assertContains(
            response,
            '<h1 class="subheader__title">'
            "Very interesting course<br>first session</h1>",
            html=True,
        )

        # Only published categories should be present on the page
        for category in categories[:2]:
            self.assertContains(
                response,
                ('<a class="category-badge" href="{:s}">'
                 '<span class="category-badge__title">{:s}</span></a>').format(
                     category.extended_object.get_absolute_url(),
                     category.extended_object.get_title(),
                 ),
                html=True,
            )
        for category in categories[-2:]:
            self.assertNotContains(response,
                                   category.extended_object.get_title())

        # Public organizations should be in response content
        for organization in organizations[:2]:
            self.assertContains(
                response,
                '<div class="organization-glimpse__title">{title:s}</div>'.
                format(title=organization.extended_object.get_title()),
                html=True,
            )

        # Draft organizations should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(response,
                                   organization.extended_object.get_title(),
                                   html=True)

        # The course run details should be on the page
        self.assertContains(
            response,
            "<strong>Enrollment starts</strong><span>Oct. 21, 2018</span>")
        self.assertContains(
            response,
            "<strong>Enrollment ends</strong><span>Jan. 18, 2019</span>")
        self.assertContains(
            response,
            "<strong>Course starts</strong><span>Dec. 10, 2018</span>")
        self.assertContains(
            response, "<strong>Course ends</strong><span>Feb. 14, 2019</span>")
        self.assertContains(
            response,
            "<strong>Languages</strong><span>English and french</span>")
コード例 #17
0
    def test_models_organization_get_persons_language_fallback_draft(self):
        """
        Validate that the reverse persons lookup works as expected with language fallback
        on a draft page.
        """
        organization1, organization2, organization3 = OrganizationFactory.create_batch(
            3, should_publish=True)
        person = PersonFactory(should_publish=True)
        placeholder = person.extended_object.placeholders.get(
            slot="organizations")
        cms_languages = {
            "default": {
                "public": True,
                "hide_untranslated": False,
                "redirect_on_fallback": False,
                "fallbacks": ["en", "fr", "de"],
            }
        }

        # Reverse plugin lookups should fallback up to the second priority language
        add_plugin(
            language="de",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization1.extended_object},
        )
        with override_settings(CMS_LANGUAGES=cms_languages):
            with translation.override("en"):
                self.assertEqual(list(organization1.get_persons()), [person])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [])

            with translation.override("fr"):
                self.assertEqual(list(organization1.get_persons()), [person])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [])

            with translation.override("de"):
                self.assertEqual(list(organization1.get_persons()), [person])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [])

        # Reverse plugin lookups should fallback to the first priority language if available
        # and ignore the second priority language unless it is the current language
        add_plugin(
            language="fr",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization2.extended_object},
        )
        with override_settings(CMS_LANGUAGES=cms_languages):
            with translation.override("en"):
                self.assertEqual(list(organization1.get_persons()), [])
                self.assertEqual(list(organization2.get_persons()), [person])
                self.assertEqual(list(organization3.get_persons()), [])

            with translation.override("fr"):
                self.assertEqual(list(organization1.get_persons()), [])
                self.assertEqual(list(organization2.get_persons()), [person])
                self.assertEqual(list(organization3.get_persons()), [])

            with translation.override("de"):
                self.assertEqual(list(organization1.get_persons()), [person])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [])

        # Reverse plugin lookups should stick to the current language if available and
        # ignore plugins on fallback languages
        add_plugin(
            language="en",
            placeholder=placeholder,
            plugin_type="OrganizationPlugin",
            **{"page": organization3.extended_object},
        )
        with override_settings(CMS_LANGUAGES=cms_languages):
            with translation.override("en"):
                self.assertEqual(list(organization1.get_persons()), [])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [person])

            with translation.override("fr"):
                self.assertEqual(list(organization1.get_persons()), [])
                self.assertEqual(list(organization2.get_persons()), [person])
                self.assertEqual(list(organization3.get_persons()), [])

            with translation.override("de"):
                self.assertEqual(list(organization1.get_persons()), [person])
                self.assertEqual(list(organization2.get_persons()), [])
                self.assertEqual(list(organization3.get_persons()), [])
コード例 #18
0
    def test_templates_course_detail_cms_draft_content(self, _):
        """
        A staff user should see a draft course including its draft elements with
        an annotation
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_subjects=subjects,
        )
        page = course.extended_object
        course_run1, _course_run2 = CourseRunFactory.create_batch(
            2, page_parent=course.extended_object, languages=["en", "fr"]
        )

        # Publish only 1 of the course runs
        course_run1.extended_object.publish("en")

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should be visible as draft to the staff user
        url = page.get_absolute_url()
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response, "<title>Very interesting course</title>", html=True
        )
        self.assertContains(
            response,
            '<h1 class="course-detail__content__title">Very interesting course</h1>',
            html=True,
        )

        # Draft and public organizations should all be present on the page
        for organization in organizations:
            self.assertContains(
                response,
                '<div class="organization-plugin__title">{title:s}</div>'.format(
                    title=organization.extended_object.get_title()
                ),
                html=True,
            )

        # Draft organizations should be annotated for styling
        self.assertContains(response, "organization-plugin-container--draft", count=2)

        # The published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<a class="subject-plugin-tag" href="{:s}">{:s}</a>'.format(
                    subject.extended_object.get_absolute_url(),
                    subject.extended_object.get_title(),
                ),
                html=True,
            )
        # Draft subjects should also be present on the page with an annotation for styling
        for subject in subjects[-2:]:
            self.assertContains(
                response,
                '<a class="{element:s} {element:s}--draft" href="{url:s}">{title:s}</a>'.format(
                    url=subject.extended_object.get_absolute_url(),
                    element="subject-plugin-tag",
                    title=subject.extended_object.get_title(),
                ),
                html=True,
            )
        # The draft and the published course runs should both be in the page
        self.assertContains(response, "Enroll now", count=2)
        self.assertContains(response, "<dd>English, French</dd>", html=True, count=2)
コード例 #19
0
    def test_templates_course_run_detail_cms_draft_content(self):
        """
        A staff user should see a draft course run including its draft elements with
        an annotation
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        categories = CategoryFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_categories=categories,
            should_publish=True,
        )
        course_run = CourseRunFactory(
            page_title="first session",
            page_parent=course.extended_object,
            resource_link="https://www.example.com/enroll",
            enrollment_start=datetime(2018, 10, 21, tzinfo=pytz.utc),
            enrollment_end=datetime(2019, 1, 18, tzinfo=pytz.utc),
            start=datetime(2018, 12, 10, tzinfo=pytz.utc),
            end=datetime(2019, 2, 14, tzinfo=pytz.utc),
            languages=["en", "fr"],
        )
        page = course_run.extended_object

        # Publish only 2 out of 4 categories and 2 out of 4 organizations
        categories[0].extended_object.publish("en")
        categories[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        categories[2].extended_object.publish("en")
        categories[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should be visible as draft to the staff user
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response,
            "<title>First session - Very interesting course</title>",
            html=True,
        )
        self.assertContains(
            response,
            '<h1 class="subheader__title">'
            "Very interesting course<br>first session</h1>",
            html=True,
        )

        # Draft and public organizations should all be present on the page
        for organization in organizations:
            self.assertContains(
                response,
                '<div class="organization-glimpse__title">{title:s}</div>'.
                format(title=organization.extended_object.get_title()),
                html=True,
            )

        # Draft organizations should be annotated for styling
        self.assertContains(response, "organization-glimpse--draft", count=2)

        # The published categories should be present on the page
        for category in categories[:2]:
            self.assertContains(
                response,
                ('<a class="category-badge" href="{:s}">'
                 '<span class="category-badge__title">{:s}</span></a>').format(
                     category.extended_object.get_absolute_url(),
                     category.extended_object.get_title(),
                 ),
                html=True,
            )

        # Draft categories should also be present on the page with an annotation for styling
        for category in categories[-2:]:
            self.assertContains(
                response,
                ('<a class="{element:s} {element:s}--draft" href="{url:s}">'
                 '<span class="category-badge__title">{title:s}</span></a>'
                 ).format(
                     url=category.extended_object.get_absolute_url(),
                     element="category-badge",
                     title=category.extended_object.get_title(),
                 ),
                html=True,
            )

        # The course run details should be on the page
        self.assertContains(
            response,
            "<strong>Enrollment starts</strong><span>Oct. 21, 2018</span>")
        self.assertContains(
            response,
            "<strong>Enrollment ends</strong><span>Jan. 18, 2019</span>")
        self.assertContains(
            response,
            "<strong>Course starts</strong><span>Dec. 10, 2018</span>")
        self.assertContains(
            response, "<strong>Course ends</strong><span>Feb. 14, 2019</span>")
        self.assertContains(
            response,
            "<strong>Languages</strong><span>English and french</span>")
コード例 #20
0
ファイル: create_demo_site.py プロジェクト: EliuFlorez/richie
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)

    # Create pages as described in PAGES_INFOS
    pages_created = recursive_page_creation(site, PAGE_INFOS)

    # Create some licences
    licences = LicenceFactory.create_batch(NB_LICENCES)

    # Create organizations under the `Organizations` page
    organizations = OrganizationFactory.create_batch(
        NB_ORGANIZATIONS,
        page_in_navigation=True,
        page_languages=["en", "fr"],
        page_parent=pages_created["organizations"],
        fill_banner=True,
        fill_description=True,
        fill_logo=True,
        should_publish=True,
    )

    # Generate each category tree and return a list of the leaf categories
    levels = list(create_categories(LEVELS_INFO, pages_created["categories"]))
    subjects = list(
        create_categories(SUBJECTS_INFO, pages_created["categories"]))

    title = PersonTitleFactory(translation=None)
    PersonTitleTranslationFactory(master=title,
                                  language_code="en",
                                  title="Doctor",
                                  abbreviation="Dr.")
    PersonTitleTranslationFactory(master=title,
                                  language_code="fr",
                                  title="Docteur",
                                  abbreviation="Dr.")

    # Create persons under the `persons` page
    persons = PersonFactory.create_batch(
        NB_PERSONS,
        page_in_navigation=True,
        page_languages=["en", "fr"],
        page_parent=pages_created["persons"],
        person_title=random.choice([title, None]),
        fill_portrait=True,
        fill_resume=True,
        should_publish=True,
    )

    # Create courses under the `Course` page with categories and organizations
    # relations
    courses = []
    for _ in range(NB_COURSES):
        video_sample = random.choice(VIDEO_SAMPLE_LINKS)

        course = CourseFactory(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["courses"],
            fill_licences=[
                ("course_license_content", random.choice(licences)),
                ("course_license_participation", random.choice(licences)),
            ],
            fill_team=random.sample(persons, NB_COURSES_PERSONS_PLUGINS),
            fill_teaser=video_sample,
            fill_cover=video_sample.image,
            fill_categories=[
                *random.sample(
                    subjects, random.randint(1, NB_COURSES_SUBJECT_RELATIONS)),
                random.choice(levels),
            ],
            fill_organizations=random.sample(
                organizations, NB_COURSES_ORGANIZATION_RELATIONS),
            fill_texts=[
                "course_syllabus",
                "course_format",
                "course_prerequisites",
                "course_plan",
                # "course_license_content",
                # "course_license_participation",
            ],
            should_publish=True,
        )
        courses.append(course)

        # Add a random number of course runs to the course
        nb_course_runs = get_number_of_course_runs()

        # 1) Make sure we have one course run open for enrollment
        now = timezone.now()
        CourseRunFactory(
            __sequence=nb_course_runs,
            page_in_navigation=False,
            page_parent=course.extended_object,
            start=now + timedelta(days=1),
            enrollment_start=now - timedelta(days=5),
            enrollment_end=now + timedelta(days=5),
            should_publish=True,
        )

        # 2) Add more random course runs
        for i in range(nb_course_runs - 1, 0, -1):
            CourseRunFactory(
                __sequence=i,
                page_in_navigation=False,
                page_languages=["en", "fr"],
                page_parent=course.extended_object,
                should_publish=True,
            )

    # 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_file = file_getter("banner")()
    wrapped_banner = File(banner_file, banner_file.name)
    banner = Image.objects.create(file=wrapped_banner)

    # - Get a logo image
    logo_file = file_getter("logo")()
    wrapped_logo = File(logo_file, logo_file.name)
    logo = Image.objects.create(file=wrapped_logo)

    # - Create the home page in each language
    for language, content in HOMEPAGE_CONTENT.items():
        # Add a banner
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LargeBannerPlugin",
            title=content["banner_title"],
            background_image=banner,
            logo=logo,
            logo_alt_text="logo",
            content=content["banner_content"],
            template=content["banner_template"],
        )
        # Add highlighted courses
        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, NB_HOME_HIGHLIGHTED_COURSES):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="CoursePlugin",
                target=courses_section,
                page=course.extended_object,
            )

        # 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,
                                          NB_HOME_HIGHLIGHTED_ORGANIZATIONS):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="OrganizationPlugin",
                target=organizations_section,
                page=organization.extended_object,
            )

        # 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, NB_HOME_HIGHLIGHTED_SUBJECTS):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="CategoryPlugin",
                target=subjects_section,
                page=subject.extended_object,
            )

        # 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, NB_HOME_HIGHLIGHTED_PERSONS):
            add_plugin(
                language=language,
                placeholder=placeholder,
                plugin_type="PersonPlugin",
                target=persons_section,
                page=person.extended_object,
            )

        # Once content has been added we must publish again homepage in every
        # edited Languages
        pages_created["home"].publish("en")
        pages_created["home"].publish("fr")
コード例 #21
0
    def test_models_category_get_organizations_descendants(self):
        """
        Related organizations should include the organizations linked to the category's
        descendants, unless specifically deactivated by the "include_descendants" argument.
        """
        category_page = create_page("Subjects",
                                    "courses/cms/category_detail.html",
                                    "en",
                                    published=True)
        category = CategoryFactory(extended_object=category_page,
                                   should_publish=True)
        organizations = OrganizationFactory.create_batch(
            2, fill_categories=[category], should_publish=True)

        child_category_page = create_page(
            "Literature",
            "courses/cms/category_detail.html",
            "en",
            parent=category_page,
            published=True,
        )
        child_category = CategoryFactory(extended_object=child_category_page,
                                         should_publish=True)
        organizations_child = OrganizationFactory.create_batch(
            2, fill_categories=[child_category], should_publish=True)

        grand_child_category_page = create_page(
            "Literature",
            "courses/cms/category_detail.html",
            "en",
            parent=child_category_page,
            published=True,
        )
        grand_child_category = CategoryFactory(
            extended_object=grand_child_category_page, should_publish=True)
        organizations_grand_child = OrganizationFactory.create_batch(
            2, fill_categories=[grand_child_category], should_publish=True)

        # Check that each category gets organizations from its descendants
        # ...unless we pass an argument to deactivate it
        self.assertEqual(
            list(category.get_organizations()),
            organizations + organizations_child + organizations_grand_child,
        )
        self.assertEqual(
            list(category.get_organizations(include_descendants=False)),
            organizations)

        self.assertEqual(
            list(child_category.get_organizations()),
            organizations_child + organizations_grand_child,
        )
        self.assertEqual(
            list(child_category.get_organizations(include_descendants=False)),
            organizations_child,
        )

        self.assertEqual(
            list(
                grand_child_category.get_organizations(
                    include_descendants=False)),
            organizations_grand_child,
        )
        self.assertEqual(list(grand_child_category.get_organizations()),
                         organizations_grand_child)
コード例 #22
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)

    # Create pages as described in PAGES_INFOS
    pages_created = recursive_page_creation(site, PAGE_INFOS)

    # Create some licences
    licences = LicenceFactory.create_batch(NB_LICENCES)

    # Create organizations under the `Organizations` page
    organizations = OrganizationFactory.create_batch(
        NB_ORGANIZATIONS,
        languages=[l[0] for l in settings.LANGUAGES],
        parent=pages_created["organizations"],
        fill_banner=True,
        fill_description=True,
        fill_logo=True,
        should_publish=True,
        in_navigation=True,
    )

    # Create subjects under the `Subjects` page
    subjects = SubjectFactory.create_batch(
        NB_SUBJECTS,
        languages=[l[0] for l in settings.LANGUAGES],
        parent=pages_created["subjects"],
        fill_banner=True,
        fill_description=True,
        fill_logo=True,
        should_publish=True,
        in_navigation=True,
    )

    # Django parler require a language to be manually set when working out of
    # request/response flow and PersonTitle use 'parler'
    translation.activate(settings.LANGUAGE_CODE)

    # Create persons under the `persons` page
    persons = PersonFactory.create_batch(
        NB_PERSONS,
        languages=[l[0] for l in settings.LANGUAGES],
        parent=pages_created["persons"],
        fill_portrait=True,
        fill_resume=True,
        should_publish=True,
        in_navigation=True,
    )

    # Create courses under the `Course` page with subjects and organizations
    # relations
    for _ in range(NB_COURSES):
        course_organizations = random.sample(
            organizations, NB_COURSES_ORGANIZATION_RELATIONS)
        video_sample = random.choice(VIDEO_SAMPLE_LINKS)

        course = CourseFactory(
            languages=[l[0] for l in settings.LANGUAGES],
            parent=pages_created["courses"],
            organization_main=random.choice(course_organizations),
            fill_licences=[
                ("course_license_content", random.choice(licences)),
                ("course_license_participation", random.choice(licences)),
            ],
            fill_team=random.sample(persons, NB_COURSES_PERSONS_PLUGINS),
            fill_teaser=video_sample,
            fill_cover=video_sample.image,
            fill_texts=[
                "course_syllabus",
                "course_format",
                "course_prerequisites",
                "course_plan",
                # "course_license_content",
                # "course_license_participation",
            ],
            with_organizations=course_organizations,
            with_subjects=random.sample(subjects,
                                        NB_COURSES_SUBJECT_RELATIONS),
            should_publish=True,
            in_navigation=True,
        )
        # Add a random number of course runs to the course
        nb_course_runs = get_number_of_course_runs()
        if nb_course_runs > 0:
            CourseRunFactory.create_batch(nb_course_runs, course=course)
コード例 #23
0
    def test_templates_person_detail_cms_published_content(self):
        """
        Validate that the important elements are displayed on a published person page
        """
        # Categories
        published_category, extra_published_category = CategoryFactory.create_batch(
            2, should_publish=True)
        unpublished_category = CategoryFactory()

        # Modify the draft version of the published category
        title_obj = published_category.extended_object.title_set.get(
            language="en")
        title_obj.title = "modified title"
        title_obj.save()

        # Organizations
        published_organization, extra_published_organization = OrganizationFactory.create_batch(
            2, should_publish=True)
        unpublished_organization = OrganizationFactory()

        # Modify the draft version of the published organization
        title_obj = published_organization.extended_object.title_set.get(
            language="en")
        title_obj.title = "modified title"
        title_obj.save()

        person = PersonFactory(
            page_title="My page title",
            fill_portrait=True,
            fill_bio=True,
            fill_categories=[published_category, unpublished_category],
            fill_organizations=[
                published_organization, unpublished_organization
            ],
        )
        page = person.extended_object

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Publish the person
        page.publish("en")

        # Add a new category to the draft person page but don't publish the modification
        placeholder = page.placeholders.get(slot="categories")
        add_plugin(
            placeholder,
            CategoryPlugin,
            "en",
            page=extra_published_category.extended_object,
        )

        # Add a new organization to the draft person page but don't publish the modification
        placeholder = page.placeholders.get(slot="organizations")
        add_plugin(
            placeholder,
            OrganizationPlugin,
            "en",
            page=extra_published_organization.extended_object,
        )

        # Ensure the published page content is correct
        response = self.client.get(url)
        self.assertContains(response,
                            "<title>My page title</title>",
                            html=True,
                            status_code=200)
        title = person.extended_object.get_title()
        self.assertContains(
            response,
            f'<h1 class="person-detail__card__content__title">{title:s}</h1>',
            html=True,
        )
        # The published category should be on the page in its published version
        self.assertContains(
            response,
            ('<a class="category-plugin-tag" href="{:s}">'
             '<div class="category-plugin-tag__title">{:s}</div></a>').format(
                 published_category.public_extension.extended_object.
                 get_absolute_url(),
                 published_category.public_extension.extended_object.get_title(
                 ),
             ),
            html=True,
        )
        # The other categories should not be leaked:
        # - new_category linked only on the draft person page
        self.assertNotContains(
            response,
            extra_published_category.extended_object.get_title(),
            html=True)
        # - unpublished category
        self.assertNotContains(
            response,
            unpublished_category.extended_object.get_title(),
            html=True)
        # - modified draft version of the published category
        self.assertNotContains(response, "modified title")

        # The published organization should be on the page in its published version
        self.assertContains(
            response,
            '<div class="organization-glimpse__title">{:s}</div>'.format(
                published_organization.public_extension.extended_object.
                get_title()),
            html=True,
        )

        # The other categories should not be leaked:
        # - new_organization linked only on the draft person page
        self.assertNotContains(
            response,
            extra_published_organization.extended_object.get_title(),
            html=True,
        )
        # - unpublished organization
        self.assertNotContains(
            response,
            unpublished_organization.extended_object.get_title(),
            html=True)
        # - modified draft version of the published organization
        self.assertNotContains(response, "modified title")
コード例 #24
0
    def test_templates_course_detail_cms_published_content(self):
        """
        Validate that the important elements are displayed on a published course page
        """
        categories = CategoryFactory.create_batch(4)
        icons = CategoryFactory.create_batch(4, fill_icon=True)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_categories=categories,
            fill_icons=icons,
        )
        page = course.extended_object
        # Create an ongoing open course run that will be published (created before
        # publishing the page)
        now = timezone.now()
        CourseRunFactory(
            direct_course=course,
            start=now - timedelta(hours=1),
            end=now + timedelta(hours=2),
            enrollment_end=now + timedelta(hours=1),
            languages=["en", "fr"],
        )

        # Publish only 2 out of 4 categories, icons and organizations
        self.assertTrue(categories[0].extended_object.publish("en"))
        self.assertTrue(categories[1].extended_object.publish("en"))
        self.assertTrue(icons[0].extended_object.publish("en"))
        self.assertTrue(icons[1].extended_object.publish("en"))
        self.assertTrue(organizations[0].extended_object.publish("en"))
        self.assertTrue(organizations[1].extended_object.publish("en"))

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        self.assertTrue(categories[2].extended_object.publish("en"))
        self.assertTrue(categories[2].extended_object.unpublish("en"))
        self.assertTrue(icons[2].extended_object.publish("en"))
        self.assertTrue(icons[2].extended_object.unpublish("en"))
        self.assertTrue(organizations[2].extended_object.publish("en"))
        self.assertTrue(organizations[2].extended_object.unpublish("en"))

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Publish and ensure content is correct
        self.assertTrue(page.publish("en"))

        # Create an unpublished ongoing open course run (created after
        # publishing the page)
        CourseRunFactory(
            direct_course=course,
            start=now - timedelta(hours=1),
            end=now + timedelta(hours=2),
            enrollment_end=now + timedelta(hours=1),
            languages=["en", "fr"],
        )

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(response,
                            "<title>Very interesting course</title>",
                            html=True)
        self.assertContains(
            response,
            '<h1 class="subheader__title">Very interesting course</h1>',
            html=True,
        )

        # Only published categories should be present on the page
        for category in categories[:2]:
            self.assertContains(
                response,
                ('<a class="category-badge" href="{:s}">'
                 '<span class="category-badge__title">{:s}</span></a>').format(
                     category.extended_object.get_absolute_url(),
                     category.extended_object.get_title(),
                 ),
                html=True,
            )
        for category in categories[-2:]:
            self.assertNotContains(response,
                                   category.extended_object.get_title())

        # Only published icons should be present on the page
        pattern = (
            r'<a.*class="category-badge".*href="{link:s}".*>'
            r'<img src="/media/filer_public_thumbnails/filer_public/.*icon\.jpg.*alt="{title:s}">'
            r'<span class="category-badge__title">'
            r".*{title:s}.*</span>")

        for icon in icons[:2]:
            self.assertIsNotNone(
                re.search(
                    pattern.format(
                        link=icon.extended_object.get_absolute_url(),
                        title=icon.extended_object.get_title(),
                    ),
                    str(response.content),
                ))
        for icon in icons[-2:]:
            self.assertNotContains(response, icon.extended_object.get_title())

        # Public organizations should be in response content
        for organization in organizations[:2]:
            self.assertContains(
                response,
                '<div class="organization-glimpse__title">{title:s}</div>'.
                format(title=organization.extended_object.get_title()),
                html=True,
            )

        # Draft organizations should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(response,
                                   organization.extended_object.get_title(),
                                   html=True)

        # Only the published course run should be in response content
        self.assertEqual(CourseRun.objects.count(), 3)
        self.assertContains(response,
                            "<dd>English and french</dd>",
                            html=True,
                            count=1)
コード例 #25
0
ファイル: create_demo_site.py プロジェクト: Verisage/richie
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)

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

    # Create some licences
    licences = LicenceFactory.create_batch(
        NB_OBJECTS["licences"], logo__file__from_path=pick_image("licence")()
    )

    # Create organizations under the `Organizations` page
    organizations = OrganizationFactory.create_batch(
        NB_OBJECTS["organizations"],
        page_in_navigation=True,
        page_languages=["en", "fr"],
        page_parent=pages_created["organizations"],
        fill_banner=pick_image("banner"),
        fill_description=True,
        fill_logo=pick_image("logo"),
        should_publish=True,
        with_permissions=True,
    )

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

    # Create persons under the `persons` page
    persons = []
    persons_for_organization = defaultdict(list)
    for _ in range(NB_OBJECTS["persons"]):
        # Randomly assign each person to a set of organizations
        person_organizations = random.sample(
            organizations,
            random.randint(1, NB_OBJECTS["person_organizations"]),  # nosec
        )
        person = PersonFactory(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["persons"],
            fill_categories=random.sample(
                subjects, random.randint(1, NB_OBJECTS["person_subjects"])  # nosec
            ),
            fill_organizations=person_organizations,
            fill_portrait=pick_image("portrait"),
            fill_bio=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 _ in range(NB_OBJECTS["courses"]):
        video_sample = random.choice(VIDEO_SAMPLE_LINKS)  # nosec

        # Randomly assign each course to a set of organizations
        course_organizations = random.sample(
            organizations, 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 = CourseFactory(
            page_in_navigation=True,
            page_languages=["en", "fr"],
            page_parent=pages_created["courses"],
            fill_licences=[
                ("course_license_content", random.choice(licences)),  # nosec
                ("course_license_participation", random.choice(licences)),  # nosec
            ],
            fill_team=random.sample(
                eligible_persons,
                min(
                    random.randint(1, 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, NB_OBJECTS["course_subjects"])  # nosec
                ),
                random.choice(levels),  # nosec
            ],
            fill_icons=random.sample(icons, get_number_of_icons()),
            fill_organizations=course_organizations,
            fill_texts=[
                "course_description",
                "course_format",
                "course_prerequisites",
                "course_plan",
                # "course_license_content",
                # "course_license_participation",
            ],
            should_publish=True,
        )
        course.create_permissions_for_organization(course_organizations[0])
        courses.append(course)

        # 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):
            CourseRunFactory(
                __sequence=i,
                languages=random.sample(
                    languages_subset, random.randint(1, len(languages_subset))  # nosec
                ),
                page_in_navigation=False,
                page_languages=["en", "fr"],
                page_parent=course.extended_object,
                should_publish=True,
            )

    # Create blog posts under the `News` page
    blogposts = []
    for _ in range(NB_OBJECTS["blogposts"]):
        post = 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(subjects, NB_OBJECTS["blogpost_categories"]),
                random.choice(levels),  # nosec
            ],
            fill_author=random.sample(persons, 1),
            should_publish=True,
        )
        blogposts.append(post)

    # 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 HOMEPAGE_CONTENT.items():
        # Add a banner
        add_plugin(
            language=language,
            placeholder=placeholder,
            plugin_type="LargeBannerPlugin",
            title=content["banner_title"],
            background_image=banner,
            logo=logo,
            logo_alt_text="logo",
            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, 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, 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 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, 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, 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, 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"],
        )

        # 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(VIDEO_SAMPLE_LINKS)  # nosec

    # - Create sample page in each language
    for language, content in 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
        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), locale=language  # nosec
        ).generate({})
        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 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)
コード例 #26
0
    def test_templates_course_run_detail_cms_published_content(self, _):
        """
        Validate that the important elements are displayed on a published course run page
        """
        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_subjects=subjects,
            should_publish=True,
        )
        course_run = CourseRunFactory(
            page_title="first session",
            page_parent=course.extended_object,
            resource_link="https://www.example.com/enroll",
            enrollment_start=datetime(2018, 10, 21),
            enrollment_end=datetime(2019, 1, 18),
            start=datetime(2018, 12, 10),
            end=datetime(2019, 2, 14),
            languages=["en", "fr"],
        )
        page = course_run.extended_object

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Now publish the page and check its content
        page.publish("en")
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response,
            "<title>First session - Very interesting course</title>",
            html=True,
        )
        self.assertContains(
            response,
            '<h1 class="course-detail__content__title">'
            "Very interesting course<br>first session</h1>",
            html=True,
        )

        # Only published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<a class="subject-plugin-tag" href="{:s}">{:s}</a>'.format(
                    subject.extended_object.get_absolute_url(),
                    subject.extended_object.get_title(),
                ),
                html=True,
            )
        for subject in subjects[-2:]:
            self.assertNotContains(response, subject.extended_object.get_title())

        # Public organizations should be in response content
        for organization in organizations[:2]:
            self.assertContains(
                response,
                '<div class="organization-plugin__title">{title:s}</div>'.format(
                    title=organization.extended_object.get_title()
                ),
                html=True,
            )

        # Draft organizations should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(
                response, organization.extended_object.get_title(), html=True
            )

        # The course run details should be on the page
        self.assertContains(
            response, "<dt>Enrollment starts</dt><dd>Oct. 21, 2018</dd>"
        )
        self.assertContains(response, "<dt>Enrollment ends</dt><dd>Jan. 18, 2019</dd>")
        self.assertContains(response, "<dt>Course starts</dt><dd>Dec. 10, 2018</dd>")
        self.assertContains(response, "<dt>Course ends</dt><dd>Feb. 14, 2019</dd>")
        self.assertContains(
            response,
            '<a class="course-detail__content__run__block__cta" '
            'href="https://www.example.com/enroll">Enroll now</a>',
            html=True,
        )
        self.assertContains(response, "<dt>Languages</dt><dd>English, French</dd>")
コード例 #27
0
    def test_templates_course_run_detail_cms_draft_content(self, _):
        """
        A staff user should see a draft course run including its draft elements with
        an annotation
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_subjects=subjects,
            should_publish=True,
        )
        course_run = CourseRunFactory(
            page_title="first session",
            page_parent=course.extended_object,
            resource_link="https://www.example.com/enroll",
            enrollment_start=datetime(2018, 10, 21),
            enrollment_end=datetime(2019, 1, 18),
            start=datetime(2018, 12, 10),
            end=datetime(2019, 2, 14),
            languages=["en", "fr"],
        )
        page = course_run.extended_object

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should be visible as draft to the staff user
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response,
            "<title>First session - Very interesting course</title>",
            html=True,
        )
        self.assertContains(
            response,
            '<h1 class="course-detail__content__title">'
            "Very interesting course<br>first session</h1>",
            html=True,
        )

        # Draft and public organizations should all be present on the page
        for organization in organizations:
            self.assertContains(
                response,
                '<div class="organization-plugin__title">{title:s}</div>'.format(
                    title=organization.extended_object.get_title()
                ),
                html=True,
            )

        # Draft organizations should be annotated for styling
        self.assertContains(response, "organization-plugin-container--draft", count=2)

        # The published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<a class="subject-plugin-tag" href="{:s}">{:s}</a>'.format(
                    subject.extended_object.get_absolute_url(),
                    subject.extended_object.get_title(),
                ),
                html=True,
            )
        # Draft subjects should also be present on the page with an annotation for styling
        for subject in subjects[-2:]:
            self.assertContains(
                response,
                '<a class="{element:s} {element:s}--draft" href="{url:s}">{title:s}</a>'.format(
                    url=subject.extended_object.get_absolute_url(),
                    element="subject-plugin-tag",
                    title=subject.extended_object.get_title(),
                ),
                html=True,
            )

        # The course run details should be on the page
        self.assertContains(
            response, "<dt>Enrollment starts</dt><dd>Oct. 21, 2018</dd>"
        )
        self.assertContains(response, "<dt>Enrollment ends</dt><dd>Jan. 18, 2019</dd>")
        self.assertContains(response, "<dt>Course starts</dt><dd>Dec. 10, 2018</dd>")
        self.assertContains(response, "<dt>Course ends</dt><dd>Feb. 14, 2019</dd>")
        self.assertContains(
            response,
            '<a class="course-detail__content__run__block__cta" '
            'href="https://www.example.com/enroll">Enroll now</a>',
            html=True,
        )
        self.assertContains(response, "<dt>Languages</dt><dd>English, French</dd>")
コード例 #28
0
    def test_templates_course_detail_cms_published_content(self, _):
        """
        Validate that the important elements are displayed on a published course page
        """
        subjects = SubjectFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_subjects=subjects,
        )
        page = course.extended_object
        course_run1, _course_run2 = CourseRunFactory.create_batch(
            2, page_parent=course.extended_object, languages=["en", "fr"]
        )
        self.assertFalse(course_run1.extended_object.publish("en"))

        # Publish only 2 out of 4 subjects and 2 out of 4 organizations
        subjects[0].extended_object.publish("en")
        subjects[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        subjects[2].extended_object.publish("en")
        subjects[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Publish and ensure content is correct
        page.publish("en")

        # Now we can publish children course runs: publish only 1 of the 2
        course_run1.extended_object.parent_page.refresh_from_db()
        self.assertTrue(course_run1.extended_object.publish("en"))

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response, "<title>Very interesting course</title>", html=True
        )
        self.assertContains(
            response,
            '<h1 class="course-detail__content__title">Very interesting course</h1>',
            html=True,
        )

        # Only published subjects should be present on the page
        for subject in subjects[:2]:
            self.assertContains(
                response,
                '<a class="subject-plugin-tag" href="{:s}">{:s}</a>'.format(
                    subject.extended_object.get_absolute_url(),
                    subject.extended_object.get_title(),
                ),
                html=True,
            )
        for subject in subjects[-2:]:
            self.assertNotContains(response, subject.extended_object.get_title())

        # Public organizations should be in response content
        for organization in organizations[:2]:
            self.assertContains(
                response,
                '<div class="organization-plugin__title">{title:s}</div>'.format(
                    title=organization.extended_object.get_title()
                ),
                html=True,
            )

        # Draft organizations should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(
                response, organization.extended_object.get_title(), html=True
            )

        # Only the published course run should be in response content
        self.assertContains(response, "Enroll now", count=1)
        self.assertContains(response, "<dd>English, French</dd>", html=True, count=1)
コード例 #29
0
    def test_templates_course_detail_cms_draft_content(self):
        """
        A staff user should see a draft course including its draft elements with
        an annotation
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        categories = CategoryFactory.create_batch(4)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_categories=categories,
        )
        page = course.extended_object
        now = timezone.now()
        CourseRunFactory(
            direct_course=course,
            start=now - timedelta(hours=1),
            end=now + timedelta(hours=2),
            enrollment_end=now + timedelta(hours=1),
            languages=["en", "fr"],
        )

        # Publish only 2 out of 4 categories and 2 out of 4 organizations
        self.assertTrue(categories[0].extended_object.publish("en"))
        self.assertTrue(categories[1].extended_object.publish("en"))
        self.assertTrue(organizations[0].extended_object.publish("en"))
        self.assertTrue(organizations[1].extended_object.publish("en"))

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        self.assertTrue(categories[2].extended_object.publish("en"))
        self.assertTrue(categories[2].extended_object.unpublish("en"))
        self.assertTrue(organizations[2].extended_object.publish("en"))
        self.assertTrue(organizations[2].extended_object.unpublish("en"))

        # The page should be visible as draft to the staff user
        url = page.get_absolute_url()
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)

        self.assertContains(response,
                            "<title>Very interesting course</title>",
                            html=True)
        self.assertContains(
            response,
            '<h1 class="subheader__title">Very interesting course</h1>',
            html=True,
        )

        # Draft and public organizations should all be present on the page
        for organization in organizations:
            self.assertContains(
                response,
                '<div class="organization-glimpse__title">{title:s}</div>'.
                format(title=organization.extended_object.get_title()),
                html=True,
            )

        # Draft organizations should be annotated for styling
        self.assertContains(response, "organization-glimpse--draft", count=2)

        # The published categories should be present on the page
        for category in categories[:2]:
            self.assertContains(
                response,
                ('<a class="category-badge" href="{:s}">'
                 '<span class="category-badge__title">{:s}</span></a>').format(
                     category.extended_object.get_absolute_url(),
                     category.extended_object.get_title(),
                 ),
                html=True,
            )
        # Draft categories should also be present on the page with an annotation for styling
        for category in categories[-2:]:
            self.assertContains(
                response,
                ('<a class="{element:s} {element:s}--draft" href="{url:s}">'
                 '<span class="category-badge__title">{title:s}</span></a>'
                 ).format(
                     url=category.extended_object.get_absolute_url(),
                     element="category-badge",
                     title=category.extended_object.get_title(),
                 ),
                html=True,
            )
        # The course run should be in the page
        self.assertContains(response,
                            "<dd>English and french</dd>",
                            html=True,
                            count=1)
コード例 #30
0
    def test_templates_course_detail_cms_published_content(self):
        """
        Validate that the important elements are displayed on a published course page
        """
        categories = CategoryFactory.create_batch(4)
        icons = CategoryFactory.create_batch(4, fill_icon=True)
        organizations = OrganizationFactory.create_batch(4)

        course = CourseFactory(
            page_title="Very interesting course",
            fill_organizations=organizations,
            fill_categories=categories,
            fill_icons=icons,
        )
        page = course.extended_object
        course_run1, _course_run2 = CourseRunFactory.create_batch(
            2, page_parent=course.extended_object, languages=["en", "fr"]
        )
        self.assertFalse(course_run1.extended_object.publish("en"))

        # Publish only 2 out of 4 categories, icons and organizations
        categories[0].extended_object.publish("en")
        categories[1].extended_object.publish("en")
        icons[0].extended_object.publish("en")
        icons[1].extended_object.publish("en")
        organizations[0].extended_object.publish("en")
        organizations[1].extended_object.publish("en")

        # The unpublished objects may have been published and unpublished which puts them in a
        # status different from objects that have never been published.
        # We want to test both cases.
        categories[2].extended_object.publish("en")
        categories[2].extended_object.unpublish("en")
        icons[2].extended_object.publish("en")
        icons[2].extended_object.unpublish("en")
        organizations[2].extended_object.publish("en")
        organizations[2].extended_object.unpublish("en")

        # The page should not be visible before it is published
        url = page.get_absolute_url()
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

        # Publish and ensure content is correct
        page.publish("en")

        # Now we can publish children course runs: publish only 1 of the 2
        course_run1.extended_object.parent_page.refresh_from_db()
        self.assertTrue(course_run1.extended_object.publish("en"))

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.assertContains(
            response, "<title>Very interesting course</title>", html=True
        )
        self.assertContains(
            response,
            '<h1 class="course-detail__content__title">Very interesting course</h1>',
            html=True,
        )

        # Only published categories should be present on the page
        for category in categories[:2]:
            self.assertContains(
                response,
                (
                    '<a class="category-plugin-tag" href="{:s}">'
                    '<div class="category-plugin-tag__title">{:s}</div></a>'
                ).format(
                    category.extended_object.get_absolute_url(),
                    category.extended_object.get_title(),
                ),
                html=True,
            )
        for category in categories[-2:]:
            self.assertNotContains(response, category.extended_object.get_title())

        # Only published icons should be present on the page
        pattern = (
            r'<a.*class="category-plugin-tag".*href="{link:s}".*>'
            r'<figure class="category-plugin-tag__figure">'
            r'<figcaption.*class="category-plugin-tag__figure__caption".*>'
            r".*{title:s}.*</figcaption>"
            r'<img src="/media/filer_public_thumbnails/filer_public/.*icon\.jpg.*alt=""/>'
        )

        for icon in icons[:2]:
            self.assertIsNotNone(
                re.search(
                    pattern.format(
                        link=icon.extended_object.get_absolute_url(),
                        title=icon.extended_object.get_title(),
                    ),
                    str(response.content),
                )
            )
        for icon in icons[-2:]:
            self.assertNotContains(response, icon.extended_object.get_title())

        # Public organizations should be in response content
        for organization in organizations[:2]:
            self.assertContains(
                response,
                '<div class="organization-glimpse__title">{title:s}</div>'.format(
                    title=organization.extended_object.get_title()
                ),
                html=True,
            )

        # Draft organizations should not be in response content
        for organization in organizations[-2:]:
            self.assertNotContains(
                response, organization.extended_object.get_title(), html=True
            )

        # Only the published course run should be in response content
        self.assertContains(response, "<dd>English and french</dd>", html=True, count=1)