예제 #1
0
    def test_signals_organizations_no_parent(self, mock_bulk, *_):
        """
        Publishing an organization should update its document in the Elasticsearch organizations
        index, and the documents for published courses to which it is related, excluding snapshots.
        """
        organization = OrganizationFactory()
        published_course, _unpublished_course = CourseFactory.create_batch(
            2, fill_organizations=[organization])
        published_course.extended_object.publish("en")
        published_course.refresh_from_db()
        self.run_commit_hooks()
        mock_bulk.reset_mock()

        organization.extended_object.publish("en")
        organization.refresh_from_db()

        # Elasticsearch should not be called before the db transaction is successful
        self.assertFalse(mock_bulk.called)
        self.run_commit_hooks()

        self.assertEqual(mock_bulk.call_count, 1)
        self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2)
        actions = list(mock_bulk.call_args[1]["actions"])
        self.assertEqual(
            actions[0]["_id"],
            str(published_course.public_extension.extended_object_id))
        self.assertEqual(actions[0]["_type"], "course")
        self.assertEqual(actions[1]["_id"], "L-0001")
        self.assertEqual(actions[1]["_type"], "organization")
예제 #2
0
    def test_signals_organizations_publish(self, mock_bulk, *_):
        """
        Publishing an organization should update its document in the Elasticsearch organizations
        index, and the documents for published courses to which it is related, excluding snapshots.
        """
        parent = OrganizationFactory(should_publish=True)
        organization = OrganizationFactory(page_parent=parent.extended_object)
        published_course, _unpublished_course = CourseFactory.create_batch(
            2, fill_organizations=[organization])
        self.assertTrue(published_course.extended_object.publish("en"))
        published_course.refresh_from_db()
        self.run_commit_hooks()
        mock_bulk.reset_mock()

        self.assertTrue(organization.extended_object.publish("en"))
        organization.refresh_from_db()

        # Elasticsearch should not be called before the db transaction is successful
        self.assertFalse(mock_bulk.called)
        self.run_commit_hooks()

        self.assertEqual(mock_bulk.call_count, 1)
        self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 3)
        actions = list(mock_bulk.call_args[1]["actions"])
        self.assertEqual(actions[0]["_id"], published_course.get_es_id())
        self.assertEqual(actions[0]["_op_type"], "index")
        self.assertEqual(actions[0]["_index"], "test_courses")
        self.assertEqual(actions[1]["_id"], organization.get_es_id())
        self.assertEqual(actions[1]["_op_type"], "index")
        self.assertEqual(actions[1]["_index"], "richie_organizations")
        self.assertEqual(actions[2]["_id"], parent.get_es_id())
        self.assertEqual(actions[2]["_op_type"], "index")
        self.assertEqual(actions[2]["_index"], "richie_organizations")
예제 #3
0
    def test_signals_organizations_unpublish(self, mock_bulk, *_):
        """
        Unpublishing an organization in a language should update its document in the Elasticsearch
        organizations index or delete it if there is no language published anymore.
        It should also reindex the documents for published courses to which it is related,
        excluding snapshots.
        """
        organization = OrganizationFactory(page_languages=["en", "fr"],
                                           should_publish=True)
        published_course, _unpublished_course = CourseFactory.create_batch(
            2, fill_organizations=[organization])
        self.assertTrue(published_course.extended_object.publish("en"))
        published_course.refresh_from_db()
        self.run_commit_hooks()
        mock_bulk.reset_mock()

        # - Unpublish the first language
        self.assertTrue(organization.extended_object.unpublish("en"))
        organization.refresh_from_db()

        # Elasticsearch should not be called before the db transaction is successful
        self.assertFalse(mock_bulk.called)
        self.run_commit_hooks()

        self.assertEqual(mock_bulk.call_count, 1)
        self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2)
        actions = list(mock_bulk.call_args[1]["actions"])
        self.assertEqual(actions[0]["_id"], published_course.get_es_id())
        self.assertEqual(actions[0]["_op_type"], "index")
        self.assertEqual(actions[0]["_index"], "test_courses")
        self.assertEqual(actions[1]["_id"], organization.get_es_id())
        self.assertEqual(actions[1]["_op_type"], "index")
        self.assertEqual(actions[1]["_index"], "richie_organizations")

        mock_bulk.reset_mock()

        # - Unpublish the second language
        self.assertTrue(organization.extended_object.unpublish("fr"))
        organization.refresh_from_db()

        # Elasticsearch should not be called before the db transaction is successful
        self.assertFalse(mock_bulk.called)
        self.run_commit_hooks()

        self.assertEqual(mock_bulk.call_count, 1)
        self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2)
        actions = list(mock_bulk.call_args[1]["actions"])
        self.assertEqual(actions[0]["_id"], published_course.get_es_id())
        self.assertEqual(actions[0]["_op_type"], "index")
        self.assertEqual(actions[0]["_index"], "test_courses")
        self.assertEqual(actions[1]["_id"], organization.get_es_id())
        self.assertEqual(actions[1]["_op_type"], "delete")
        self.assertEqual(actions[1]["_index"], "richie_organizations")
예제 #4
0
    def test_course_change_view_get(self):
        """
        The admin change view should include the editable and readonly fields as expected.
        In particular, the relation fields should only include options for related objects in
        their draft version.
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        # Create a course
        course = CourseFactory()

        # Create an organization and publish it
        organization = OrganizationFactory()
        organization.extended_object.publish("en")
        organization.refresh_from_db()

        # Create a subject and publish it
        subject = SubjectFactory()
        subject.extended_object.publish("en")
        subject.refresh_from_db()

        # Get the admin change view
        url = reverse("admin:courses_course_change", args=[course.id])
        response = self.client.get(url)

        # Check that the page includes all our fields
        self.assertContains(
            response, course.extended_object.get_title(), status_code=200
        )
        self.assertContains(response, course.active_session)
        self.assertContains(
            response, course.organization_main.extended_object.get_title()
        )
        # Only the draft organization and subject should be proposed as options in select boxes
        self.assertContains(
            response, '<option value="{:d}">{!s}'.format(subject.id, subject)
        )
        self.assertNotContains(
            response,
            '<option value="{:d}">{!s}'.format(
                subject.public_extension.id, subject.public_extension
            ),
        )
        self.assertContains(
            response, '<option value="{:d}">{!s}'.format(organization.id, organization)
        )
        self.assertNotContains(
            response,
            '<option value="{:d}">{!s}'.format(
                organization.public_extension.id, organization.public_extension
            ),
        )
예제 #5
0
    def test_admin_organization_change_view_post(self):
        """
        Validate that the organization can be updated via the admin.
        """
        user = UserFactory(is_staff=True, is_superuser=True)
        self.client.login(username=user.username, password="******")

        # Create an organization
        organization = OrganizationFactory()

        # Get the admin change view
        url = reverse("admin:courses_organization_change", args=[organization.id])
        data = {"code": " r5G yç👷学pm 44 "}
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 302)

        # Check that the organization was updated as expected
        organization.refresh_from_db()
        self.assertEqual(organization.code, "R5G-YÇ学PM-44")
예제 #6
0
    def test_cms_plugins_organization_render_on_public_page(self):
        """
        The organization plugin should render as expected on a public page.
        """
        # Create a filer fake image
        image = FilerImageFactory()

        # Create an organization
        organization = OrganizationFactory(page_title={
            "en": "public title",
            "fr": "titre publique"
        })
        organization_page = organization.extended_object

        # Add logo to related placeholder
        logo_placeholder = organization_page.placeholders.get(slot="logo")
        add_plugin(
            logo_placeholder, PicturePlugin, "en", **{
                "picture": image,
                "attributes": {
                    "alt": "logo description"
                }
            })
        add_plugin(
            logo_placeholder, PicturePlugin, "fr", **{
                "picture": image,
                "attributes": {
                    "alt": "description du logo"
                }
            })

        # Create a page to add the plugin to
        page = create_i18n_page({"en": "A page", "fr": "Une page"})
        placeholder = page.placeholders.get(slot="maincontent")
        add_plugin(placeholder, OrganizationPlugin, "en",
                   **{"page": organization_page})
        add_plugin(placeholder, OrganizationPlugin, "fr",
                   **{"page": organization_page})

        organization_page.publish("en")
        organization_page.publish("fr")
        organization.refresh_from_db()

        page.publish("en")
        page.publish("fr")

        # Check the page content in English
        url = page.get_absolute_url(language="en")

        # The organization plugin should not be visible on the public page before it is published
        organization_page.unpublish("en")
        response = self.client.get(url)
        self.assertNotContains(response, "public title")

        # # Republish the plugin
        organization_page.publish("en")

        # Now modify the organization to have a draft different from the public version
        title_obj = organization_page.get_title_obj(language="en")
        title_obj.tile = "draft title"
        title_obj.save()

        # Publishing the page again should make the plugin public
        page.publish("en")

        # Check the page content in English
        response = self.client.get(url)
        # The organization's name should be present as a link to the cms page
        # And CMS page title should be in title attribute of the link
        self.assertContains(
            response,
            '<a class="organization-plugin__body" href="/en/public-title/" title="{:s}"'
            .format(organization.public_extension.extended_object.get_title()),
            status_code=200,
        )
        # The organization's title should be wrapped in a div
        self.assertContains(
            response,
            '<div class="organization-plugin__title">{:s}</div>'.format(
                organization.public_extension.extended_object.get_title()),
            html=True,
        )
        self.assertNotContains(response, "draft title")

        # Organziation's logo should be present
        # pylint: disable=no-member
        self.assertContains(response, image.file.name)

        # Same checks in French
        url = page.get_absolute_url(language="fr")
        response = self.client.get(url)
        self.assertContains(
            response,
            '<a class="organization-plugin__body" href="/fr/titre-publique/" title="{:s}"'
            .format(organization.public_extension.extended_object.get_title()),
            status_code=200,
        )
        # pylint: disable=no-member
        self.assertContains(response, image.file.name)
예제 #7
0
    def test_cms_plugins_organization_render_on_public_page(self):
        """
        The organization plugin should render as expected on a public page.
        """
        # Create an organization
        organization = OrganizationFactory(
            page_title={
                "en": "public title",
                "fr": "titre public"
            },
            fill_logo={
                "original_filename": "logo.jpg",
                "default_alt_text": "my logo"
            },
        )
        organization_page = organization.extended_object

        # Create a page to add the plugin to
        page = create_i18n_page({"en": "A page", "fr": "Une page"})
        placeholder = page.placeholders.get(slot="maincontent")
        add_plugin(placeholder, OrganizationPlugin, "en",
                   **{"page": organization_page})
        add_plugin(placeholder, OrganizationPlugin, "fr",
                   **{"page": organization_page})

        organization_page.publish("en")
        organization_page.publish("fr")
        organization.refresh_from_db()

        page.publish("en")
        page.publish("fr")

        # Check the page content in English
        url = page.get_absolute_url(language="en")

        # The organization plugin should not be visible on the public page before it is published
        organization_page.unpublish("en")
        response = self.client.get(url)
        self.assertNotContains(response, "public title")

        # # Republish the plugin
        organization_page.publish("en")

        # Now modify the organization to have a draft different from the public version
        title_obj = organization_page.get_title_obj(language="en")
        title_obj.title = "draft title"
        title_obj.save()

        # Publishing the page again should make the plugin public
        page.publish("en")

        # Check the page content in English
        response = self.client.get(url)
        # The organization's name should be present as a link to the cms page
        # And CMS page title should be in title attribute of the link
        self.assertIn(
            '<a class=" organization-glimpse organization-glimpse--link " '
            'href="/en/public-title/"',
            re.sub(" +", " ",
                   str(response.content).replace("\\n", "")),
        )

        # The organization's title should be wrapped in a div
        self.assertContains(
            response,
            '<div class="organization-glimpse__title">{:s}</div>'.format(
                organization.public_extension.extended_object.get_title()),
            html=True,
        )
        self.assertNotContains(response, "draft title")

        # Organziation's logo should be present
        pattern = (
            r'<div class="organization-glimpse__logo">'
            r'<img src="/media/filer_public_thumbnails/filer_public/.*logo\.jpg__200x113'
            r'.*alt=""')
        self.assertIsNotNone(re.search(pattern, str(response.content)))

        # Same checks in French
        url = page.get_absolute_url(language="fr")
        response = self.client.get(url)
        self.assertIn(
            '<a class=" organization-glimpse organization-glimpse--link " '
            'href="/fr/titre-public/"',
            re.sub(" +", " ",
                   str(response.content).replace("\\n", "")),
        )
        pattern = (
            r'<div class="organization-glimpse__logo">'
            r'<img src="/media/filer_public_thumbnails/filer_public/.*logo\.jpg__200x113'
            r'.*alt=""')
        self.assertIsNotNone(re.search(pattern, str(response.content)))