예제 #1
0
    def test_publish_content_medium_tuto(self):
        # 3. Medium-size tutorial
        midsize_tuto = PublishableContentFactory(type="TUTORIAL")

        midsize_tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=midsize_tuto.gallery,
                           user=self.user_author,
                           mode="W")
        midsize_tuto.licence = self.licence
        midsize_tuto.save()

        # populate with 2 chapters (1 extract each)
        midsize_tuto_draft = midsize_tuto.load_version()
        chapter1 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto)
        ExtractFactory(container=chapter2, db_object=midsize_tuto)

        # publish it
        midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk)
        published = publish_content(midsize_tuto, midsize_tuto_draft)

        self.assertEqual(published.content, midsize_tuto)
        self.assertEqual(published.content_pk, midsize_tuto.pk)
        self.assertEqual(published.content_type, midsize_tuto.type)
        self.assertEqual(published.content_public_slug,
                         midsize_tuto_draft.slug)
        self.assertEqual(published.sha_public, midsize_tuto.sha_draft)

        public = midsize_tuto.load_version(sha=published.sha_public,
                                           public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # it's a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test creation of files:
        self.assertTrue(Path(published.get_prod_path()).is_dir())
        self.assertTrue(
            Path(published.get_prod_path(), "manifest.json").is_file())

        self.assertTrue(
            Path(public.get_prod_path(), public.introduction).is_file())
        self.assertTrue(
            Path(public.get_prod_path(), public.conclusion).is_file())

        self.assertEqual(len(public.children), 2)
        for child in public.children:
            self.assertTrue(os.path.isfile(
                child.get_prod_path()))  # an HTML file for each chapter
            self.assertIsNone(child.introduction)
            self.assertIsNone(child.conclusion)
예제 #2
0
 def test_image_with_non_ascii_chars(self):
     """seen on #4144"""
     article = PublishableContentFactory(type="article",
                                         author_list=[self.user_author])
     image_string = (
         "![Portrait de Richard Stallman en 2014. [Source](https://commons.wikimedia.org/wiki/"
         "File:Richard_Stallman_-_Fête_de_l%27Humanité_2014_-_010.jpg).]"
         "(/media/galleries/4410/c1016bf1-a1de-48a1-9ef1-144308e8725d.jpg)")
     article.sha_draft = article.load_version().repo_update(
         article.title, image_string, "", update_slug=False)
     article.save()
     publish_content(article, article.load_version())
     self.assertTrue(
         PublishedContent.objects.filter(content_id=article.pk).exists())
예제 #3
0
    def test_content_ordering(self):
        category_1 = ContentCategoryFactory()
        category_2 = ContentCategoryFactory()
        subcategory_1 = SubCategoryFactory(category=category_1)
        subcategory_1.position = 5
        subcategory_1.save()
        subcategory_2 = SubCategoryFactory(category=category_1)
        subcategory_2.position = 1
        subcategory_2.save()
        subcategory_3 = SubCategoryFactory(category=category_2)

        tuto_1 = PublishableContentFactory(type="TUTORIAL")
        tuto_1.subcategory.add(subcategory_1)
        tuto_1_draft = tuto_1.load_version()
        publish_content(tuto_1, tuto_1_draft, is_major_update=True)

        top_categories_tuto = topbar_publication_categories("TUTORIAL").get(
            "categories")
        expected = [(subcategory_1.title, subcategory_1.slug, category_1.slug)]
        self.assertEqual(top_categories_tuto[category_1.title], expected)

        tuto_2 = PublishableContentFactory(type="TUTORIAL")
        tuto_2.subcategory.add(subcategory_2)
        tuto_2_draft = tuto_2.load_version()
        publish_content(tuto_2, tuto_2_draft, is_major_update=True)

        top_categories_tuto = topbar_publication_categories("TUTORIAL").get(
            "categories")
        # New subcategory is now first is the list
        expected.insert(
            0, (subcategory_2.title, subcategory_2.slug, category_1.slug))
        self.assertEqual(top_categories_tuto[category_1.title], expected)

        article_1 = PublishableContentFactory(type="TUTORIAL")
        article_1.subcategory.add(subcategory_3)
        article_1_draft = tuto_2.load_version()
        publish_content(article_1, article_1_draft, is_major_update=True)

        # New article has no impact
        top_categories_tuto = topbar_publication_categories("TUTORIAL").get(
            "categories")
        self.assertEqual(top_categories_tuto[category_1.title], expected)

        top_categories_contents = topbar_publication_categories(
            ["TUTORIAL", "ARTICLE"]).get("categories")
        expected_2 = [(subcategory_3.title, subcategory_3.slug,
                       category_2.slug)]
        self.assertEqual(top_categories_contents[category_1.title], expected)
        self.assertEqual(top_categories_contents[category_2.title], expected_2)
    def test_opinion_publication_staff(self):
        """
        Test the publication of PublishableContent where type is OPINION (with staff).
        """

        text_publication = "Aussi tôt dit, aussi tôt fait !"

        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_staff)

        result = self.client.post(
            reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}),
            {"text": text_publication, "source": "", "version": opinion_draft.current_version},
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version)
예제 #5
0
    def test_extract_is_none(self):
        """Test the case of a null extract"""

        article = PublishableContentFactory(type="ARTICLE")
        versioned = article.load_version()

        given_title = "Peu importe, en fait, ça compte peu"
        some_text = "Disparaitra aussi vite que possible"

        # add a new extract with `None` for text
        version = versioned.repo_add_extract(given_title, None)

        # check on the model:
        new_extract = versioned.children[-1]
        self.assertIsNone(new_extract.text)

        # it remains when loading the manifest!
        versioned2 = article.load_version(sha=version)
        self.assertIsNotNone(versioned2)
        self.assertIsNone(versioned.children[-1].text)

        version = new_extract.repo_update(given_title, None)
        self.assertIsNone(new_extract.text)

        # it remains
        versioned2 = article.load_version(sha=version)
        self.assertIsNotNone(versioned2)
        self.assertIsNone(versioned.children[-1].text)

        version = new_extract.repo_update(given_title, some_text)
        self.assertIsNotNone(new_extract.text)
        self.assertEqual(some_text, new_extract.get_text())

        # now it changes
        versioned2 = article.load_version(sha=version)
        self.assertIsNotNone(versioned2)
        self.assertIsNotNone(versioned.children[-1].text)

        # ... and lets go back
        version = new_extract.repo_update(given_title, None)
        self.assertIsNone(new_extract.text)

        # it has changed
        versioned2 = article.load_version(sha=version)
        self.assertIsNotNone(versioned2)
        self.assertIsNone(versioned.children[-1].text)
예제 #6
0
 def _create_and_publish_type_in_subcategory(self, content_type,
                                             subcategory):
     tuto_1 = PublishableContentFactory(type=content_type,
                                        author_list=[self.user_author])
     tuto_1.subcategory.add(subcategory)
     tuto_1.save()
     tuto_1_draft = tuto_1.load_version()
     tuto_1.public_version = publish_content(tuto_1,
                                             tuto_1_draft,
                                             is_major_update=True)
     tuto_1.save()
예제 #7
0
 def get_small_opinion(self):
     """
     Returns a published opinion without extract.
     """
     opinion = PublishableContentFactory(type="OPINION")
     opinion.authors.add(self.user_author)
     UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W")
     opinion.licence = LicenceFactory()
     opinion.save()
     opinion_draft = opinion.load_version()
     return publish_content(opinion, opinion_draft)
예제 #8
0
    def create_multiple_tags(self, number_of_tags=REST_PAGE_SIZE):
        tags = []
        for tag in range(0, number_of_tags):
            tags.append("number" + str(tag))

        # Prepare content containing all the tags
        content = PublishableContentFactory(type="TUTORIAL")
        content.add_tags(tags)
        content.save()
        content_draft = content.load_version()

        # then, publish it !
        publish_content(content, content_draft)
    def test_permanently_unpublish_opinion(self):
        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}),
            {"source": "", "version": opinion_draft.current_version},
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # login as staff
        self.client.force_login(self.user_staff)

        # unpublish opinion
        result = self.client.post(
            reverse("validation:ignore-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}),
            {
                "operation": "REMOVE_PUB",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # refresh
        opinion = PublishableContent.objects.get(pk=opinion.pk)

        # check that the opinion is not published
        self.assertFalse(opinion.in_public())

        # check that it's impossible to publish the opinion again
        result = self.client.get(opinion.get_absolute_url())
        self.assertContains(result, _("Billet modéré"))  # front

        result = self.client.post(
            reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}),
            {"source": "", "version": opinion_draft.current_version},
            follow=False,
        )
        self.assertEqual(result.status_code, 403)  # back
예제 #10
0
    def get_published_content(self, author, user_staff, nb_part=1, nb_chapter=1, nb_extract=1):
        bigtuto = PublishableContentFactory(type="TUTORIAL")

        bigtuto.authors.add(author)
        UserGalleryFactory(gallery=bigtuto.gallery, user=author, mode="W")
        bigtuto.licence = LicenceFactory()
        bigtuto.save()

        # populate the bigtuto
        bigtuto_draft = bigtuto.load_version()
        for i in range(nb_part):
            part = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto)
            for j in range(nb_chapter):
                chapter = ContainerFactory(parent=part, db_object=bigtuto)
                for k in range(nb_extract):
                    ExtractFactory(container=chapter, db_object=bigtuto)

        # connect with author:
        self.client.force_login(author)

        # ask validation
        self.client.post(
            reverse("validation:ask", kwargs={"pk": bigtuto.pk, "slug": bigtuto.slug}),
            {"text": "ask for validation", "source": "", "version": bigtuto_draft.current_version},
            follow=False,
        )

        # login with staff and publish
        self.client.force_login(user_staff)

        validation = Validation.objects.filter(content=bigtuto).last()

        self.client.post(
            reverse("validation:reserve", kwargs={"pk": validation.pk}), {"version": validation.version}, follow=False
        )

        # accept
        self.client.post(
            reverse("validation:accept", kwargs={"pk": validation.pk}),
            {"text": "accept validation", "is_major": True, "source": ""},
            follow=False,
        )
        self.client.logout()

        published = PublishedContent.objects.filter(content=bigtuto).first()
        self.assertIsNotNone(published)
        return published
예제 #11
0
 def test_tagged_tree_extract(self):
     midsize = PublishableContentFactory(author_list=[self.user_author])
     midsize_draft = midsize.load_version()
     first_container = ContainerFactory(parent=midsize_draft,
                                        db_object=midsize)
     second_container = ContainerFactory(parent=midsize_draft,
                                         db_object=midsize)
     first_extract = ExtractFactory(container=first_container,
                                    db_object=midsize)
     second_extract = ExtractFactory(container=second_container,
                                     db_object=midsize)
     tagged_tree = get_target_tagged_tree_for_extract(
         first_extract, midsize_draft)
     paths = {i[0]: i[3] for i in tagged_tree}
     self.assertTrue(paths[second_extract.get_full_slug()])
     self.assertFalse(paths[second_container.get_path(True)])
     self.assertFalse(paths[first_container.get_path(True)])
예제 #12
0
    def create_content(self):
        """
        Returns a content and its draft used in following tests.
        """
        tuto = PublishableContentFactory(type="TUTORIAL",
                                         intro="Intro tuto",
                                         conclusion="Conclusion tuto")
        tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=tuto.gallery,
                           user=self.user_author,
                           mode="W")
        tuto.licence = self.licence
        tuto.save()

        tuto_draft = tuto.load_version()

        return tuto, tuto_draft
예제 #13
0
    def test_collaborative_article_edition_and_editor_persistence(self):
        selenium = self.selenium
        find_element = selenium.find_element_by_css_selector

        author = ProfileFactory()

        article = PublishableContentFactory(type="ARTICLE",
                                            author_list=[author.user])

        versioned_article = article.load_version()
        article.sha_draft = versioned_article.repo_update("article",
                                                          "",
                                                          "",
                                                          update_slug=False)
        article.save()

        article_edit_url = reverse("content:edit",
                                   args=[article.pk, article.slug])

        self.login(author)
        selenium.execute_script('localStorage.setItem("editor_choice", "new")'
                                )  # we want the new editor
        selenium.get(self.live_server_url + article_edit_url)

        intro = find_element("div#div_id_introduction div.CodeMirror")
        # ActionChains: Support for CodeMirror https://stackoverflow.com/a/48969245/2226755
        action_chains = ActionChains(selenium)
        scrollDriverTo(selenium, 0, 312)
        action_chains.click(intro).perform()
        action_chains.send_keys("intro").perform()

        output = "div#div_id_introduction div.CodeMirror div.CodeMirror-code"
        self.assertEqual("intro", find_element(output).text)

        article.sha_draft = versioned_article.repo_update("article",
                                                          "new intro",
                                                          "",
                                                          update_slug=False)
        article.save()

        selenium.refresh()

        self.assertEqual(
            "new intro",
            find_element(".md-editor#id_introduction").get_attribute("value"))
예제 #14
0
    def test_char_count_after_publication(self):
        """Test the ``get_char_count()`` function.

        Special care should be taken with this function, since:

        - The username of the author is, by default "Firmxxx" where "xxx" depends on the tests before ;
        - The titles (!) also contains a number that also depends on the number of tests before ;
        - The date is ``datetime.now()`` and contains the months, which is never a fixed number of letters.
        """

        author = ProfileFactory().user
        author.username = "******"
        author.save()

        len_date_now = len(date(datetime.now(), "d F Y"))

        article = PublishedContentFactory(type="ARTICLE",
                                          author_list=[author],
                                          title="Un titre")
        published = PublishedContent.objects.filter(content=article).first()
        self.assertEqual(published.get_char_count(), 160 + len_date_now)

        tuto = PublishableContentFactory(type="TUTORIAL",
                                         author_list=[author],
                                         title="Un titre")

        # add a chapter, so it becomes a middle tutorial
        tuto_draft = tuto.load_version()
        chapter1 = ContainerFactory(parent=tuto_draft,
                                    db_object=tuto,
                                    title="Un chapitre")
        ExtractFactory(container=chapter1, db_object=tuto, title="Un extrait")
        published = publish_content(tuto, tuto_draft, is_major_update=True)

        tuto.sha_public = tuto_draft.current_version
        tuto.sha_draft = tuto_draft.current_version
        tuto.public_version = published
        tuto.save()

        published = PublishedContent.objects.filter(content=tuto).first()
        self.assertEqual(published.get_char_count(), 335 + len_date_now)
예제 #15
0
    def test_cancel_pick_operation(self):
        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # login as staff
        self.client.force_login(self.user_staff)

        # PICK
        result = self.client.post(
            reverse("validation:pick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # cancel the operation
        operation = PickListOperation.objects.latest("operation_date")
        result = self.client.post(reverse("validation:revoke-ignore-opinion",
                                          kwargs={"pk": operation.pk}),
                                  follow=False)
        self.assertEqual(result.status_code, 200)

        # refresh
        operation = PickListOperation.objects.get(pk=operation.pk)
        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertFalse(operation.is_effective)
        self.assertEqual(self.user_staff, operation.canceler_user)
        self.assertIsNone(opinion.sha_picked)

        # NO_PICK
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "NO_PICK",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # cancel the operation
        operation = PickListOperation.objects.latest("operation_date")
        result = self.client.post(reverse("validation:revoke-ignore-opinion",
                                          kwargs={"pk": operation.pk}),
                                  follow=False)
        self.assertEqual(result.status_code, 200)

        # check that the opinion is displayed on validation page
        result = self.client.get(reverse("validation:list-opinion"))
        self.assertContains(result, opinion.title)

        # REMOVE_PUB
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "REMOVE_PUB",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # cancel the operation
        operation = PickListOperation.objects.latest("operation_date")
        result = self.client.post(reverse("validation:revoke-ignore-opinion",
                                          kwargs={"pk": operation.pk}),
                                  follow=False)
        self.assertEqual(result.status_code, 200)

        # check that the opinion can be published again
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)
예제 #16
0
    def test_publish_content_change_title_before_watchdog(
            self, opinions_management):
        """
        Test we can publish a content, change its title and publish it again
        right away, before the publication watchdog processed the first
        publication.
        """
        previous_extra_content_generation_policy = self.overridden_zds_app[
            "content"]["extra_content_generation_policy"]
        self.overridden_zds_app["content"][
            "extra_content_generation_policy"] = "WATCHDOG"

        # Create a content:
        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()

        # Publish it a first time:
        self.client.force_login(self.user_author)

        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": "Blabla",
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # Change the title:
        random = "Whatever, we don't care about the details"
        result = self.client.post(
            reverse("content:edit", args=[opinion.pk, opinion.slug]),
            {
                "title": "{} ({})".format(opinion.title, "modified"),
                "description": random,
                "introduction": random,
                "conclusion": random,
                "type": "OPINION",
                "licence": opinion.licence.pk,
                "subcategory": opinion.subcategory.first().pk,
                "last_hash": opinion.load_version().compute_hash(),
                "image":
                (settings.BASE_DIR / "fixtures" / "logo.png").open("rb"),
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)
        self.assertEqual(PublishedContent.objects.count(), 1)
        self.assertEqual(opinions_management.send.call_count, 1)
        self.assertEqual(opinions_management.send.call_args[1]["action"],
                         "publish")

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # and publish it a second time now it has a new title:
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": "Blabla",
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # There are two PublishedContent: one with the old title and the old slug
        # redirecting to the current version of the content with the new title:
        self.assertEqual(PublishedContent.objects.count(), 2)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        opinion_draft = opinion.load_version()
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        requested_events = PublicationEvent.objects.filter(
            state_of_processing="REQUESTED")
        self.assertEqual(requested_events.count(), 4)

        # Now, call the watchdog:
        call_command("publication_watchdog", "--once")

        requested_events = PublicationEvent.objects.filter(
            state_of_processing="REQUESTED")
        self.assertEqual(requested_events.count(), 0)

        self.overridden_zds_app["content"][
            "extra_content_generation_policy"] = previous_extra_content_generation_policy
예제 #17
0
    def test_defenitely_unpublish_alerted_opinion(self):
        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # login as staff
        self.client.force_login(self.user_staff)
        alerter = ProfileFactory().user
        Alert.objects.create(
            author=alerter,
            scope="CONTENT",
            content=opinion,
            pubdate=datetime.datetime.now(),
            text="J'ai un probleme avec cette opinion : c'est pas la mienne.",
        )
        # unpublish opinion
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "REMOVE_PUB",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # refresh
        opinion = PublishableContent.objects.get(pk=opinion.pk)

        # check that the opinion is not published
        self.assertFalse(opinion.in_public())

        # check that it's impossible to publish the opinion again
        result = self.client.get(opinion.get_absolute_url())
        self.assertContains(result, _("Billet modéré"))  # front

        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)  # back
        self.assertTrue(Alert.objects.filter(content=opinion).last().solved)
        # check alert page is still accessible and our alert is well displayed
        resp = self.client.get(reverse("pages-alerts"))
        self.assertEqual(200, resp.status_code)
        self.assertEqual(0, len(resp.context["alerts"]))
        self.assertEqual(1, len(resp.context["solved"]))
예제 #18
0
    def test_ignore_opinion(self):
        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # ignore with author => 403
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "NO_PICK",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)

        # now, login as staff
        self.client.force_login(self.user_staff)

        # check that the opinion is displayed
        result = self.client.get(reverse("validation:list-opinion"))
        self.assertContains(result, opinion.title)

        # ignore the opinion
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "NO_PICK",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # check that the opinion is not displayed
        result = self.client.get(reverse("validation:list-opinion"))
        self.assertNotContains(result, opinion.title)

        # publish the opinion again
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # check that the opinion is displayed
        result = self.client.get(reverse("validation:list-opinion"))
        self.assertContains(result, opinion.title)

        # reject it
        result = self.client.post(
            reverse("validation:ignore-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "operation": "REJECT",
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 200)

        # publish again
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        # check that the opinion is not displayed
        result = self.client.get(reverse("validation:list-opinion"))
        self.assertNotContains(result, opinion.title)
예제 #19
0
    def test_opinion_validation(self):
        """
        Test the validation of PublishableContent where type is OPINION.
        """

        text_publication = "Aussi tôt dit, aussi tôt fait !"

        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_publication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # valid with author => 403
        opinion = PublishableContent.objects.get(pk=opinion.pk)
        opinion_draft = opinion.load_version()

        result = self.client.post(
            reverse("validation:pick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNone(opinion.sha_picked)
        self.assertIsNone(opinion.picked_date)

        self.client.force_login(self.user_staff)

        # valid with staff
        result = self.client.post(
            reverse("validation:pick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertEqual(opinion.sha_picked, opinion_draft.current_version)
        self.assertIsNotNone(opinion.picked_date)

        # invalid with author => 403
        self.client.force_login(self.user_author)

        result = self.client.post(
            reverse("validation:unpick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": "Parce que je veux",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertEqual(opinion.sha_picked, opinion_draft.current_version)

        # invalid with staff
        self.client.force_login(self.user_staff)

        result = self.client.post(
            reverse("validation:unpick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": "Parce que je peux !",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNone(opinion.sha_picked)

        # double invalidation wont work
        result = self.client.post(
            reverse("validation:unpick-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": "Parce que je peux toujours ...",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)
예제 #20
0
    def test_opinion_unpublication(self, opinions_management):
        """
        Test the unpublication of PublishableContent where type is OPINION (with author).
        """

        text_publication = "Aussi tôt dit, aussi tôt fait !"
        text_unpublication = "Au revoir !"

        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        # author

        self.client.force_login(self.user_author)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_publication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)
        self.assertEqual(opinions_management.send.call_count, 1)
        self.assertEqual(opinions_management.send.call_args[1]["action"],
                         "publish")

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # unpublish
        result = self.client.post(
            reverse("validation:unpublish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_unpublication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 0)
        self.assertEqual(opinions_management.send.call_count, 2)
        self.assertEqual(opinions_management.send.call_args[1]["action"],
                         "unpublish")

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNone(opinion.public_version)

        # staff

        self.client.force_login(self.user_staff)

        # publish
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_publication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # unpublish
        result = self.client.post(
            reverse("validation:unpublish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_unpublication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 0)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNone(opinion.public_version)

        # guest => 403

        self.client.force_login(self.user_author)

        # publish with author
        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_publication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        self.client.force_login(self.user_guest)

        # unpublish
        result = self.client.post(
            reverse("validation:unpublish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_unpublication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 403)

        self.assertEqual(PublishedContent.objects.count(), 1)
예제 #21
0
    def test_opinion_alert(self):
        """Test content alert"""

        text_publication = "Aussi tôt dit, aussi tôt fait !"

        opinion = PublishableContentFactory(type="OPINION")

        opinion.authors.add(self.user_author)
        UserGalleryFactory(gallery=opinion.gallery,
                           user=self.user_author,
                           mode="W")
        opinion.licence = self.licence
        opinion.save()

        opinion_draft = opinion.load_version()
        ExtractFactory(container=opinion_draft, db_object=opinion)
        ExtractFactory(container=opinion_draft, db_object=opinion)

        self.client.force_login(self.user_author)

        result = self.client.post(
            reverse("validation:publish-opinion",
                    kwargs={
                        "pk": opinion.pk,
                        "slug": opinion.slug
                    }),
            {
                "text": text_publication,
                "source": "",
                "version": opinion_draft.current_version
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        self.assertEqual(PublishedContent.objects.count(), 1)

        opinion = PublishableContent.objects.get(pk=opinion.pk)
        self.assertIsNotNone(opinion.public_version)
        self.assertEqual(opinion.public_version.sha_public,
                         opinion_draft.current_version)

        # Alert content
        random_user = ProfileFactory().user

        self.client.force_login(random_user)

        result = self.client.post(reverse("content:alert-content",
                                          kwargs={"pk": opinion.pk}),
                                  {"signal_text": "Yeurk !"},
                                  follow=False)

        self.assertEqual(result.status_code, 302)
        self.assertIsNotNone(
            Alert.objects.filter(author__pk=random_user.pk,
                                 content__pk=opinion.pk).first())

        alert = Alert.objects.filter(author__pk=random_user.pk,
                                     content__pk=opinion.pk).first()
        self.assertFalse(alert.solved)

        result = self.client.post(
            reverse("content:resolve-content", kwargs={"pk": opinion.pk}),
            {
                "alert_pk": alert.pk,
                "text": "Je peux ?"
            },
            follow=False,
        )
        self.assertEqual(result.status_code,
                         403)  # solving the alert by yourself wont work

        alert = Alert.objects.get(pk=alert.pk)
        self.assertFalse(alert.solved)

        self.client.force_login(self.user_staff)

        result = self.client.post(
            reverse("content:resolve-content", kwargs={"pk": opinion.pk}),
            {
                "alert_pk": alert.pk,
                "text": "Anéfé!"
            },
            follow=False,
        )
        self.assertEqual(result.status_code, 302)

        alert = Alert.objects.get(pk=alert.pk)
        self.assertTrue(alert.solved)
예제 #22
0
    def test_upercase_and_lowercase_search_give_same_results(self):
        """Pretty self-explanatory function name, isn't it ?"""

        if not self.manager.connected_to_es:
            return

        # 1. Index lowercase stuffs
        text_lc = "test"

        topic_1_lc = TopicFactory(forum=self.forum,
                                  author=self.user,
                                  title=text_lc)

        tag_lc = TagFactory(title=text_lc)
        topic_1_lc.tags.add(tag_lc)
        topic_1_lc.subtitle = text_lc
        topic_1_lc.save()

        post_1_lc = PostFactory(topic=topic_1_lc, author=self.user, position=1)
        post_1_lc.text = post_1_lc.text_html = text_lc
        post_1_lc.save()

        tuto_lc = PublishableContentFactory(type="TUTORIAL")
        tuto_draft_lc = tuto_lc.load_version()

        tuto_lc.title = text_lc
        tuto_lc.authors.add(self.user)
        subcategory_lc = SubCategoryFactory(title=text_lc)
        tuto_lc.subcategory.add(subcategory_lc)
        tuto_lc.tags.add(tag_lc)
        tuto_lc.save()

        tuto_draft_lc.description = text_lc
        tuto_draft_lc.repo_update_top_container(text_lc, tuto_lc.slug, text_lc,
                                                text_lc)

        chapter1_lc = ContainerFactory(parent=tuto_draft_lc, db_object=tuto_lc)
        extract_lc = ExtractFactory(container=chapter1_lc, db_object=tuto_lc)
        extract_lc.repo_update(text_lc, text_lc)

        published_lc = publish_content(tuto_lc,
                                       tuto_draft_lc,
                                       is_major_update=True)

        tuto_lc.sha_public = tuto_draft_lc.current_version
        tuto_lc.sha_draft = tuto_draft_lc.current_version
        tuto_lc.public_version = published_lc
        tuto_lc.save()

        # 2. Index uppercase stuffs
        text_uc = "TEST"

        topic_1_uc = TopicFactory(forum=self.forum,
                                  author=self.user,
                                  title=text_uc)

        topic_1_uc.tags.add(
            tag_lc)  # Note: a constraint forces tags title to be unique
        topic_1_uc.subtitle = text_uc
        topic_1_uc.save()

        post_1_uc = PostFactory(topic=topic_1_uc, author=self.user, position=1)
        post_1_uc.text = post_1_uc.text_html = text_uc
        post_1_uc.save()

        tuto_uc = PublishableContentFactory(type="TUTORIAL")
        tuto_draft_uc = tuto_uc.load_version()

        tuto_uc.title = text_uc
        tuto_uc.authors.add(self.user)
        tuto_uc.subcategory.add(subcategory_lc)
        tuto_uc.tags.add(tag_lc)
        tuto_uc.save()

        tuto_draft_uc.description = text_uc
        tuto_draft_uc.repo_update_top_container(text_uc, tuto_uc.slug, text_uc,
                                                text_uc)

        chapter1_uc = ContainerFactory(parent=tuto_draft_uc, db_object=tuto_uc)
        extract_uc = ExtractFactory(container=chapter1_uc, db_object=tuto_uc)
        extract_uc.repo_update(text_uc, text_uc)

        published_uc = publish_content(tuto_uc,
                                       tuto_draft_uc,
                                       is_major_update=True)

        tuto_uc.sha_public = tuto_draft_uc.current_version
        tuto_uc.sha_draft = tuto_draft_uc.current_version
        tuto_uc.public_version = published_uc
        tuto_uc.save()

        # 3. Index and search:
        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 0)

        # index
        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model)
        self.manager.refresh_index()

        result = self.client.get(reverse("search:query") + "?q=" + text_lc,
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response_lc = result.context["object_list"].execute()
        self.assertEqual(response_lc.hits.total, 8)

        result = self.client.get(reverse("search:query") + "?q=" + text_uc,
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response_uc = result.context["object_list"].execute()
        self.assertEqual(response_uc.hits.total, 8)

        for responses in zip(
                response_lc,
                response_uc):  # we should get results in the same order!
            self.assertEqual(responses[0].meta.id, responses[1].meta.id)
예제 #23
0
    def test_change_publishedcontents_impacts_chapter(self):

        if not self.manager.connected_to_es:
            return

        # 1. Create middle-size content and index it
        text = "test"

        tuto = PublishableContentFactory(type="TUTORIAL")
        tuto_draft = tuto.load_version()

        tuto.title = text
        tuto.authors.add(self.user)
        tuto.save()

        tuto_draft.repo_update_top_container(
            text, tuto.slug, text,
            text)  # change title to be sure it will match

        chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        chapter1.repo_update(text, text, text)
        extract = ExtractFactory(container=chapter1, db_object=tuto)
        extract.repo_update(text, text)

        published = publish_content(tuto, tuto_draft, is_major_update=True)

        tuto.sha_public = tuto_draft.current_version
        tuto.sha_draft = tuto_draft.current_version
        tuto.public_version = published
        tuto.save()

        self.manager.es_bulk_indexing_of_model(PublishedContent)
        self.manager.refresh_index()

        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 2)  # indexing ok

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()

        self.assertEqual(response.hits.total, 2)

        chapters = [r for r in response if r.meta.doc_type == "chapter"]
        self.assertEqual(chapters[0].meta.doc_type,
                         FakeChapter.get_es_document_type())
        self.assertEqual(chapters[0].meta.id,
                         published.content_public_slug + "__" + chapter1.slug)

        # 2. Change tuto: delete chapter and insert new one !
        tuto = PublishableContent.objects.get(pk=tuto.pk)
        tuto_draft = tuto.load_version()

        tuto_draft.children[0].repo_delete()  # chapter 1 is gone !

        another_text = "another thing"
        self.assertTrue(
            text not in another_text
        )  # to prevent a future modification from breaking this test

        chapter2 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        chapter2.repo_update(another_text, another_text, another_text)
        extract2 = ExtractFactory(container=chapter2, db_object=tuto)
        extract2.repo_update(another_text, another_text)

        published = publish_content(tuto, tuto_draft, is_major_update=False)

        tuto.sha_public = tuto_draft.current_version
        tuto.sha_draft = tuto_draft.current_version
        tuto.public_version = published
        tuto.save()

        self.manager.es_bulk_indexing_of_model(PublishedContent)
        self.manager.refresh_index()

        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 2)  # 2 objects, not 3 !

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()

        contents = [r for r in response if r.meta.doc_type != "chapter"]
        self.assertEqual(response.hits.total,
                         len(contents))  # no chapter found anymore

        result = self.client.get(reverse("search:query") + "?q=" +
                                 another_text + "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()
        chapters = [r for r in response if r.meta.doc_type == "chapter"]
        self.assertEqual(response.hits.total, 1)
        self.assertEqual(chapters[0].meta.doc_type,
                         FakeChapter.get_es_document_type())
        self.assertEqual(chapters[0].meta.id, published.content_public_slug +
                         "__" + chapter2.slug)  # got new chapter
예제 #24
0
    def test_basic_search(self):
        """Basic search and filtering"""

        if not self.manager.connected_to_es:
            return

        # 1. Index and test search:
        text = "test"

        topic_1 = TopicFactory(forum=self.forum, author=self.user, title=text)
        post_1 = PostFactory(topic=topic_1, author=self.user, position=1)
        post_1.text = post_1.text_html = text
        post_1.save()

        # create a middle-size content and publish it
        tuto = PublishableContentFactory(type="TUTORIAL")
        tuto_draft = tuto.load_version()

        tuto.title = text
        tuto.authors.add(self.user)
        tuto.save()

        tuto_draft.repo_update_top_container(
            text, tuto.slug, text,
            text)  # change title to be sure it will match

        chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        extract = ExtractFactory(container=chapter1, db_object=tuto)
        extract.repo_update(text, text)

        published = publish_content(tuto, tuto_draft, is_major_update=True)

        tuto.sha_public = tuto_draft.current_version
        tuto.sha_draft = tuto_draft.current_version
        tuto.public_version = published
        tuto.save()

        # nothing has been indexed yet:
        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 0)

        # index
        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model)
        self.manager.refresh_index()

        result = self.client.get(reverse("search:query") + "?q=" + text,
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()

        self.assertEqual(response.hits.total, 4)  # get 4 results

        # 2. Test filtering:
        topic_1 = Topic.objects.get(pk=topic_1.pk)
        post_1 = Post.objects.get(pk=post_1.pk)
        published = PublishedContent.objects.get(pk=published.pk)

        ids = {
            "topic": [topic_1.es_id],
            "post": [post_1.es_id],
            "content": [
                published.es_id,
                published.content_public_slug + "__" + chapter1.slug
            ],
        }

        search_groups = [
            k for k, v in settings.ZDS_APP["search"]["search_groups"].items()
        ]
        group_to_model = {
            k: v[1]
            for k, v in settings.ZDS_APP["search"]["search_groups"].items()
        }

        for doc_type in search_groups:
            result = self.client.get(reverse("search:query") + "?q=" + text +
                                     "&models=" + doc_type,
                                     follow=False)
            self.assertEqual(result.status_code, 200)

            response = result.context["object_list"].execute()

            self.assertEqual(response.hits.total,
                             len(ids[doc_type]))  # get 1 result of each …
            for i, r in enumerate(response):
                self.assertIn(
                    r.meta.doc_type,
                    group_to_model[doc_type])  # … and only of the right type …
                self.assertEqual(r.meta.id,
                                 ids[doc_type][i])  # … with the right id !
예제 #25
0
    def test_boosts(self):
        """Check if boosts are doing their job"""

        if not self.manager.connected_to_es:
            return

        # 1. Create topics (with identical titles), posts (with identical texts), an article and a tuto
        text = "test"

        topic_1_solved_sticky = TopicFactory(forum=self.forum,
                                             author=self.user)
        topic_1_solved_sticky.title = text
        topic_1_solved_sticky.subtitle = ""
        topic_1_solved_sticky.solved_by = self.user
        topic_1_solved_sticky.is_sticky = True
        topic_1_solved_sticky.save()

        post_1 = PostFactory(topic=topic_1_solved_sticky,
                             author=self.user,
                             position=1)
        post_1.text = post_1.text_html = text
        post_1.save()

        post_2_useful = PostFactory(topic=topic_1_solved_sticky,
                                    author=self.user,
                                    position=2)
        post_2_useful.text = post_2_useful.text_html = text
        post_2_useful.is_useful = True
        post_2_useful.like = 5
        post_2_useful.dislike = 2  # l/d ratio above 1
        post_2_useful.save()

        topic_2_locked = TopicFactory(forum=self.forum,
                                      author=self.user,
                                      title=text)
        topic_2_locked.title = text
        topic_2_locked.subtitle = ""
        topic_2_locked.is_locked = True
        topic_2_locked.save()

        post_3_ld_below_1 = PostFactory(topic=topic_2_locked,
                                        author=self.user,
                                        position=1)
        post_3_ld_below_1.text = post_3_ld_below_1.text_html = text
        post_3_ld_below_1.like = 2
        post_3_ld_below_1.dislike = 5  # l/d ratio below 1
        post_3_ld_below_1.save()

        tuto = PublishableContentFactory(type="TUTORIAL")
        tuto_draft = tuto.load_version()

        tuto.title = text
        tuto.authors.add(self.user)
        tuto.save()

        tuto_draft.repo_update_top_container(text, tuto.slug, text, text)

        chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        chapter1.repo_update(text, "Who cares ?", "Same here")
        ExtractFactory(container=chapter1, db_object=tuto)

        published_tuto = publish_content(tuto,
                                         tuto_draft,
                                         is_major_update=True)

        tuto.sha_public = tuto_draft.current_version
        tuto.sha_draft = tuto_draft.current_version
        tuto.public_version = published_tuto
        tuto.save()

        article = PublishedContentFactory(type="ARTICLE", title=text)
        published_article = PublishedContent.objects.get(content_pk=article.pk)

        opinion_not_picked = PublishedContentFactory(type="OPINION",
                                                     title=text)
        published_opinion_not_picked = PublishedContent.objects.get(
            content_pk=opinion_not_picked.pk)

        opinion_picked = PublishedContentFactory(type="OPINION", title=text)
        opinion_picked.sha_picked = opinion_picked.sha_draft
        opinion_picked.date_picked = datetime.datetime.now()
        opinion_picked.save()

        published_opinion_picked = PublishedContent.objects.get(
            content_pk=opinion_picked.pk)

        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model)
        self.manager.refresh_index()

        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 10)

        # 2. Reset all boosts to 1
        for doc_type in settings.ZDS_APP["search"]["boosts"]:
            for key in settings.ZDS_APP["search"]["boosts"][doc_type]:
                settings.ZDS_APP["search"]["boosts"][doc_type][key] = 1.0

        # 3. Test posts
        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Post.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 3)

        # score are equals without boost:
        self.assertTrue(response[0].meta.score == response[1].meta.score ==
                        response[2].meta.score)

        settings.ZDS_APP["search"]["boosts"]["post"]["if_first"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Post.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 3)

        self.assertTrue(response[0].meta.score == response[1].meta.score >
                        response[2].meta.score)
        self.assertEqual(response[2].meta.id, str(
            post_2_useful.pk))  # post 2 is the only one not first

        settings.ZDS_APP["search"]["boosts"]["post"]["if_first"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["post"]["if_useful"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Post.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 3)

        self.assertTrue(response[0].meta.score > response[1].meta.score ==
                        response[2].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(post_2_useful.pk))  # post 2 is useful

        settings.ZDS_APP["search"]["boosts"]["post"]["if_useful"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["post"]["ld_ratio_above_1"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Post.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 3)

        self.assertTrue(response[0].meta.score > response[1].meta.score ==
                        response[2].meta.score)
        self.assertEqual(response[0].meta.id, str(
            post_2_useful.pk))  # post 2 have a l/d ratio of 5/2

        settings.ZDS_APP["search"]["boosts"]["post"]["ld_ratio_above_1"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["post"][
            "ld_ratio_below_1"] = 2.0  # no one would do that in real life

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Post.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 3)

        self.assertTrue(response[0].meta.score > response[1].meta.score ==
                        response[2].meta.score)
        self.assertEqual(response[0].meta.id, str(
            post_3_ld_below_1.pk))  # post 3 have a l/d ratio of 2/5

        settings.ZDS_APP["search"]["boosts"]["post"]["ld_ratio_below_1"] = 1.0

        # 4. Test topics
        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Topic.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        # score are equals without boost:
        self.assertTrue(response[0].meta.score == response[1].meta.score)

        settings.ZDS_APP["search"]["boosts"]["topic"]["if_sticky"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Topic.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(topic_1_solved_sticky.pk))  # topic 1 is sticky

        settings.ZDS_APP["search"]["boosts"]["topic"]["if_sticky"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["topic"]["if_solved"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Topic.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(topic_1_solved_sticky.pk))  # topic 1 is solved

        settings.ZDS_APP["search"]["boosts"]["topic"]["if_solved"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["topic"][
            "if_locked"] = 2.0  # no one would do that in real life

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=" + Topic.get_es_document_type(),
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(topic_2_locked.pk))  # topic 2 is locked

        settings.ZDS_APP["search"]["boosts"]["topic"][
            "if_locked"] = 1.0  # no one would do that in real life

        # 5. Test published contents
        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 5)

        # score are equals without boost:
        self.assertTrue(
            response[0].meta.score == response[1].meta.score == response[2].
            meta.score == response[3].meta.score == response[4].meta.score)

        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_article"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 5)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(published_article.pk))  # obvious

        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_article"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_tutorial"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 5)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(published_tuto.pk))  # obvious

        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_tutorial"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_opinion"] = 2.0
        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_opinion_not_picked"] = 4.0
        # Note: in "real life", unpicked opinion would get a boost < 1.

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 5)

        self.assertTrue(response[0].meta.score > response[1].meta.score >
                        response[2].meta.score)
        self.assertEqual(
            response[0].meta.id,
            str(published_opinion_not_picked.pk))  # unpicked opinion got first
        self.assertEqual(response[1].meta.id, str(published_opinion_picked.pk))

        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_opinion"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_opinion_not_picked"] = 1.0
        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_medium_or_big_tutorial"] = 2.0

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&models=content",
                                 follow=False)

        self.assertEqual(result.status_code, 200)
        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 5)

        self.assertTrue(response[0].meta.score > response[1].meta.score)
        self.assertEqual(response[0].meta.id,
                         str(published_tuto.pk))  # obvious

        settings.ZDS_APP["search"]["boosts"]["publishedcontent"][
            "if_medium_or_big_tutorial"] = 1.0

        # 6. Test global boosts
        # NOTE: score are NOT the same for all documents, no matter how hard it tries to, small differences exists

        for model in self.indexable:

            # set a huge number to overcome the small differences:
            settings.ZDS_APP["search"]["boosts"][
                model.get_es_document_type()]["global"] = 10.0

            result = self.client.get(reverse("search:query") + "?q=" + text,
                                     follow=False)

            self.assertEqual(result.status_code, 200)
            response = result.context["object_list"].execute()
            self.assertEqual(response.hits.total, 10)

            self.assertEqual(response[0].meta.doc_type,
                             model.get_es_document_type())  # obvious

            settings.ZDS_APP["search"]["boosts"][
                model.get_es_document_type()]["global"] = 1.0
예제 #26
0
    def test_category_and_subcategory_impact_search(self):
        """If two contents do not belong to the same (sub)category"""

        if not self.manager.connected_to_es:
            return

        text = "Did you ever hear the tragedy of Darth Plagueis The Wise?"

        # 1. Create two contents with different subcategories
        category_1 = "category 1"
        subcategory_1 = SubCategoryFactory(title=category_1)
        category_2 = "category 2"
        subcategory_2 = SubCategoryFactory(title=category_2)

        tuto_1 = PublishableContentFactory(type="TUTORIAL")
        tuto_1_draft = tuto_1.load_version()

        tuto_1.title = text
        tuto_1.authors.add(self.user)
        tuto_1.subcategory.add(subcategory_1)
        tuto_1.save()

        tuto_1_draft.description = text
        tuto_1_draft.repo_update_top_container(text, tuto_1.slug, text, text)

        chapter_1 = ContainerFactory(parent=tuto_1_draft, db_object=tuto_1)
        extract_1 = ExtractFactory(container=chapter_1, db_object=tuto_1)
        extract_1.repo_update(text, text)

        published_1 = publish_content(tuto_1,
                                      tuto_1_draft,
                                      is_major_update=True)

        tuto_1.sha_public = tuto_1_draft.current_version
        tuto_1.sha_draft = tuto_1_draft.current_version
        tuto_1.public_version = published_1
        tuto_1.save()

        tuto_2 = PublishableContentFactory(type="TUTORIAL")
        tuto_2_draft = tuto_2.load_version()

        tuto_2.title = text
        tuto_2.authors.add(self.user)
        tuto_2.subcategory.add(subcategory_2)
        tuto_2.save()

        tuto_2_draft.description = text
        tuto_2_draft.repo_update_top_container(text, tuto_2.slug, text, text)

        chapter_2 = ContainerFactory(parent=tuto_2_draft, db_object=tuto_2)
        extract_2 = ExtractFactory(container=chapter_2, db_object=tuto_2)
        extract_2.repo_update(text, text)

        published_2 = publish_content(tuto_2,
                                      tuto_2_draft,
                                      is_major_update=True)

        tuto_2.sha_public = tuto_2_draft.current_version
        tuto_2.sha_draft = tuto_2_draft.current_version
        tuto_2.public_version = published_2
        tuto_2.save()

        # 2. Index:
        self.assertEqual(
            len(
                self.manager.setup_search(Search().query(
                    MatchAll())).execute()), 0)

        # index
        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model)
        self.manager.refresh_index()

        result = self.client.get(reverse("search:query") + "?q=" + text,
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 4)  # Ok

        # 3. Test
        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&model=content&subcategory=" +
                                 subcategory_1.slug,
                                 follow=False)

        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        self.assertEqual([
            int(r.meta.id) for r in response
            if r.meta.doc_type == "publishedcontent"
        ][0], published_1.pk)
        self.assertEqual([
            r.meta.id for r in response if r.meta.doc_type == "chapter"
        ][0], tuto_1.slug + "__" + chapter_1.slug)

        result = self.client.get(reverse("search:query") + "?q=" + text +
                                 "&model=content&subcategory=" +
                                 subcategory_2.slug,
                                 follow=False)

        self.assertEqual(result.status_code, 200)

        response = result.context["object_list"].execute()
        self.assertEqual(response.hits.total, 2)

        self.assertEqual([
            int(r.meta.id) for r in response
            if r.meta.doc_type == "publishedcontent"
        ][0], published_2.pk)
        self.assertEqual([
            r.meta.id for r in response if r.meta.doc_type == "chapter"
        ][0], tuto_2.slug + "__" + chapter_2.slug)
예제 #27
0
class UtilsTests(TutorialTestMixin, TestCase):
    def setUp(self):
        self.mas = ProfileFactory().user
        self.overridden_zds_app["member"]["bot_account"] = self.mas.username

        self.licence = LicenceFactory()

        self.user_author = ProfileFactory().user
        self.staff = StaffProfileFactory().user

        self.tuto = PublishableContentFactory(type="TUTORIAL")
        self.tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=self.tuto.gallery,
                           user=self.user_author,
                           mode="W")
        self.tuto.licence = self.licence
        self.tuto.save()

        self.tuto_draft = self.tuto.load_version()
        self.part1 = ContainerFactory(parent=self.tuto_draft,
                                      db_object=self.tuto)
        self.chapter1 = ContainerFactory(parent=self.part1,
                                         db_object=self.tuto)
        self.old_registry = {
            key: value
            for key, value in PublicatorRegistry.get_all_registered()
        }

        class TestPdfPublicator(Publicator):
            def publish(self, md_file_path, base_name, **kwargs):
                with Path(base_name + ".pdf").open("w") as f:
                    f.write("bla")
                shutil.copy2(
                    str(Path(base_name + ".pdf")),
                    str(Path(md_file_path.replace("__building", "")).parent))

        PublicatorRegistry.registry["pdf"] = TestPdfPublicator()

    def test_get_target_tagged_tree_for_container(self):
        part2 = ContainerFactory(parent=self.tuto_draft,
                                 db_object=self.tuto,
                                 title="part2")
        part3 = ContainerFactory(parent=self.tuto_draft,
                                 db_object=self.tuto,
                                 title="part3")
        tagged_tree = get_target_tagged_tree_for_container(
            self.part1, self.tuto_draft)

        self.assertEqual(4, len(tagged_tree))
        paths = {i[0]: i[3] for i in tagged_tree}
        self.assertTrue(part2.get_path(True) in paths)
        self.assertTrue(part3.get_path(True) in paths)
        self.assertTrue(self.chapter1.get_path(True) in paths)
        self.assertTrue(self.part1.get_path(True) in paths)
        self.assertFalse(self.tuto_draft.get_path(True) in paths)
        self.assertFalse(paths[self.chapter1.get_path(True)],
                         "can't be moved to a too deep container")
        self.assertFalse(paths[self.part1.get_path(True)],
                         "can't be moved after or before himself")
        self.assertTrue(paths[part2.get_path(True)],
                        "can be moved after or before part2")
        self.assertTrue(paths[part3.get_path(True)],
                        "can be moved after or before part3")
        tagged_tree = get_target_tagged_tree_for_container(
            part3, self.tuto_draft)
        self.assertEqual(4, len(tagged_tree))
        paths = {i[0]: i[3] for i in tagged_tree}
        self.assertTrue(part2.get_path(True) in paths)
        self.assertTrue(part3.get_path(True) in paths)
        self.assertTrue(self.chapter1.get_path(True) in paths)
        self.assertTrue(self.part1.get_path(True) in paths)
        self.assertFalse(self.tuto_draft.get_path(True) in paths)
        self.assertTrue(paths[self.chapter1.get_path(True)],
                        "can't be moved to a too deep container")
        self.assertTrue(paths[self.part1.get_path(True)],
                        "can't be moved after or before himself")
        self.assertTrue(paths[part2.get_path(True)],
                        "can be moved after or before part2")
        self.assertFalse(paths[part3.get_path(True)],
                         "can be moved after or before part3")

    def test_publish_content_article(self):
        """test and ensure the behavior of ``publish_content()`` and ``unpublish_content()``"""

        # 1. Article:
        article = PublishableContentFactory(type="ARTICLE")

        article.authors.add(self.user_author)
        UserGalleryFactory(gallery=article.gallery,
                           user=self.user_author,
                           mode="W")
        article.licence = self.licence
        article.save()

        # populate the article
        article_draft = article.load_version()
        ExtractFactory(container=article_draft, db_object=article)
        ExtractFactory(container=article_draft, db_object=article)

        self.assertEqual(len(article_draft.children), 2)

        # publish !
        article = PublishableContent.objects.get(pk=article.pk)
        published = publish_content(article, article_draft)

        self.assertEqual(published.content, article)
        self.assertEqual(published.content_pk, article.pk)
        self.assertEqual(published.content_type, article.type)
        self.assertEqual(published.content_public_slug, article_draft.slug)
        self.assertEqual(published.sha_public, article.sha_draft)

        public = article.load_version(sha=published.sha_public,
                                      public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # it's a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test object created in database
        self.assertEqual(
            PublishedContent.objects.filter(content=article).count(), 1)
        published = PublishedContent.objects.filter(content=article).last()

        self.assertEqual(published.content_pk, article.pk)
        self.assertEqual(published.content_public_slug, article_draft.slug)
        self.assertEqual(published.content_type, article.type)
        self.assertEqual(published.sha_public, public.current_version)

        # test creation of files:
        self.assertTrue(os.path.isdir(published.get_prod_path()))
        self.assertTrue(
            os.path.isfile(
                os.path.join(published.get_prod_path(), "manifest.json")))
        prod_path = public.get_prod_path()
        self.assertTrue(prod_path.endswith(".html"), prod_path)
        self.assertTrue(os.path.isfile(prod_path),
                        prod_path)  # normally, an HTML file should exists
        self.assertIsNone(
            public.introduction
        )  # since all is in the HTML file, introduction does not exists anymore
        self.assertIsNone(public.conclusion)
        article.public_version = published
        article.save()
        # depublish it !
        unpublish_content(article)
        self.assertEqual(
            PublishedContent.objects.filter(content=article).count(),
            0)  # published object disappear
        self.assertFalse(os.path.exists(
            public.get_prod_path()))  # article was removed
        # ... For the next tests, I will assume that the unpublication works.

    def test_publish_content_medium_tuto(self):
        # 3. Medium-size tutorial
        midsize_tuto = PublishableContentFactory(type="TUTORIAL")

        midsize_tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=midsize_tuto.gallery,
                           user=self.user_author,
                           mode="W")
        midsize_tuto.licence = self.licence
        midsize_tuto.save()

        # populate with 2 chapters (1 extract each)
        midsize_tuto_draft = midsize_tuto.load_version()
        chapter1 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto)
        ExtractFactory(container=chapter2, db_object=midsize_tuto)

        # publish it
        midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk)
        published = publish_content(midsize_tuto, midsize_tuto_draft)

        self.assertEqual(published.content, midsize_tuto)
        self.assertEqual(published.content_pk, midsize_tuto.pk)
        self.assertEqual(published.content_type, midsize_tuto.type)
        self.assertEqual(published.content_public_slug,
                         midsize_tuto_draft.slug)
        self.assertEqual(published.sha_public, midsize_tuto.sha_draft)

        public = midsize_tuto.load_version(sha=published.sha_public,
                                           public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # it's a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test creation of files:
        self.assertTrue(Path(published.get_prod_path()).is_dir())
        self.assertTrue(
            Path(published.get_prod_path(), "manifest.json").is_file())

        self.assertTrue(
            Path(public.get_prod_path(), public.introduction).is_file())
        self.assertTrue(
            Path(public.get_prod_path(), public.conclusion).is_file())

        self.assertEqual(len(public.children), 2)
        for child in public.children:
            self.assertTrue(os.path.isfile(
                child.get_prod_path()))  # an HTML file for each chapter
            self.assertIsNone(child.introduction)
            self.assertIsNone(child.conclusion)

    def test_publish_content_big_tuto(self):
        # 4. Big tutorial:
        bigtuto = PublishableContentFactory(type="TUTORIAL")

        bigtuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=bigtuto.gallery,
                           user=self.user_author,
                           mode="W")
        bigtuto.licence = self.licence
        bigtuto.save()

        # populate with 2 part (1 chapter with 1 extract each)
        bigtuto_draft = bigtuto.load_version()
        part1 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto)
        chapter1 = ContainerFactory(parent=part1, db_object=bigtuto)
        ExtractFactory(container=chapter1, db_object=bigtuto)
        part2 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto)
        chapter2 = ContainerFactory(parent=part2, db_object=bigtuto)
        ExtractFactory(container=chapter2, db_object=bigtuto)

        # publish it
        bigtuto = PublishableContent.objects.get(pk=bigtuto.pk)
        published = publish_content(bigtuto, bigtuto_draft)

        self.assertEqual(published.content, bigtuto)
        self.assertEqual(published.content_pk, bigtuto.pk)
        self.assertEqual(published.content_type, bigtuto.type)
        self.assertEqual(published.content_public_slug, bigtuto_draft.slug)
        self.assertEqual(published.sha_public, bigtuto.sha_draft)

        public = bigtuto.load_version(sha=published.sha_public,
                                      public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # it's a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test creation of files:
        self.assertTrue(os.path.isdir(published.get_prod_path()))
        self.assertTrue(
            os.path.isfile(
                os.path.join(published.get_prod_path(), "manifest.json")))

        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.introduction)))
        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.conclusion)))

        self.assertEqual(len(public.children), 2)
        for part in public.children:
            self.assertTrue(os.path.isdir(
                part.get_prod_path()))  # a directory for each part
            # ... and an HTML file for introduction and conclusion
            self.assertTrue(
                os.path.isfile(
                    os.path.join(public.get_prod_path(), part.introduction)))
            self.assertTrue(
                os.path.isfile(
                    os.path.join(public.get_prod_path(), part.conclusion)))

            self.assertEqual(len(part.children), 1)

            for chapter in part.children:
                # the HTML file is located in the good directory:
                self.assertEqual(part.get_prod_path(),
                                 os.path.dirname(chapter.get_prod_path()))
                self.assertTrue(os.path.isfile(
                    chapter.get_prod_path()))  # an HTML file for each chapter
                self.assertIsNone(chapter.introduction)
                self.assertIsNone(chapter.conclusion)

    def test_export_only_ready_to_publish(self):
        """
        Test exported contents contain only ready_to_publish==True parts.
        """

        # We save the current settings for the PDF publicator:
        previous_pdf_publicator = PublicatorRegistry.get("pdf")
        previous_build_pdf_when_published = self.overridden_zds_app["content"][
            "build_pdf_when_published"]
        # We need to produce at least the LaTeX file, so we use the real PDF publicator:
        PublicatorRegistry.registry["pdf"] = ZMarkdownRebberLatexPublicator(
            ".pdf")
        self.overridden_zds_app["content"]["build_pdf_when_published"] = True

        #  Medium-size tutorial
        midsize_tuto = PublishableContentFactory(type="TUTORIAL")

        midsize_tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=midsize_tuto.gallery,
                           user=self.user_author,
                           mode="W")
        midsize_tuto.licence = self.licence
        midsize_tuto.save()

        # populate with 3 chapters (1 extract each), one not being ready for pubication
        midsize_tuto_draft = midsize_tuto.load_version()
        chapter1 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto,
                                    title="Chapter 1 ready")
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto,
                                    title="Chapter 2 ready")
        ExtractFactory(container=chapter2, db_object=midsize_tuto)
        chapter3 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_object=midsize_tuto,
                                    title="Chapter 3 not ready")
        chapter3.ready_to_publish = False
        ExtractFactory(container=chapter3, db_object=midsize_tuto)

        # publish it
        midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk)
        published = publish_content(midsize_tuto, midsize_tuto_draft)
        public = midsize_tuto.load_version(sha=published.sha_public,
                                           public=published)

        # test creation of files:
        self.assertTrue(Path(published.get_prod_path()).is_dir())
        self.assertTrue(
            Path(published.get_prod_path(), "manifest.json").is_file())

        self.assertTrue(
            Path(public.get_prod_path(), public.introduction).is_file())
        self.assertTrue(
            Path(public.get_prod_path(), public.conclusion).is_file())

        self.assertEqual(len(public.children), 2)
        for child in public.children:
            self.assertTrue(os.path.isfile(
                child.get_prod_path()))  # an HTML file for each chapter
            self.assertIsNone(child.introduction)
            self.assertIsNone(child.conclusion)

        # Test Markdown content:
        self.assertTrue(published.has_md())
        with Path(published.get_extra_contents_directory(),
                  published.content_public_slug + ".md").open("r") as md:
            content = md.read()
            self.assertIn(chapter1.title, content)
            self.assertIn(chapter2.title, content)
            self.assertNotIn(chapter3.title, content)

        # TODO: factorize getting the LaTeX file path with what is done in zds.tutorialv2.publication_utils.publish_content()
        tmp_path = os.path.join(
            settings.ZDS_APP["content"]["repo_public_path"],
            published.content_public_slug + "__building")
        build_extra_contents_path = os.path.join(
            tmp_path, settings.ZDS_APP["content"]["extra_contents_dirname"])
        base_name = os.path.join(build_extra_contents_path,
                                 published.content_public_slug)
        tex_file = base_name + ".tex"
        # PDF generation may fail, we only test the LaTeX content:
        with open(tex_file) as tex:
            content = tex.read()
            self.assertIn(chapter1.title, content)
            self.assertIn(chapter2.title, content)
            self.assertNotIn(chapter3.title, content)

        # We set back the previous settings:
        PublicatorRegistry.registry["pdf"] = previous_pdf_publicator
        self.overridden_zds_app["content"][
            "build_pdf_when_published"] = previous_build_pdf_when_published

    def test_tagged_tree_extract(self):
        midsize = PublishableContentFactory(author_list=[self.user_author])
        midsize_draft = midsize.load_version()
        first_container = ContainerFactory(parent=midsize_draft,
                                           db_object=midsize)
        second_container = ContainerFactory(parent=midsize_draft,
                                            db_object=midsize)
        first_extract = ExtractFactory(container=first_container,
                                       db_object=midsize)
        second_extract = ExtractFactory(container=second_container,
                                        db_object=midsize)
        tagged_tree = get_target_tagged_tree_for_extract(
            first_extract, midsize_draft)
        paths = {i[0]: i[3] for i in tagged_tree}
        self.assertTrue(paths[second_extract.get_full_slug()])
        self.assertFalse(paths[second_container.get_path(True)])
        self.assertFalse(paths[first_container.get_path(True)])

    def test_update_manifest(self):
        opts = {}
        path_manifest1 = settings.BASE_DIR / "fixtures" / "tuto" / "balise_audio" / "manifest.json"
        path_manifest2 = settings.BASE_DIR / "fixtures" / "tuto" / "balise_audio" / "manifest2.json"
        args = [str(path_manifest2)]
        shutil.copy(path_manifest1, path_manifest2)
        LicenceFactory(code="CC BY")
        call_command("upgrade_manifest_to_v2", *args, **opts)
        manifest = path_manifest2.open("r")
        json = json_handler.loads(manifest.read())

        self.assertTrue("version" in json)
        self.assertTrue("licence" in json)
        self.assertTrue("children" in json)
        self.assertEqual(len(json["children"]), 3)
        self.assertEqual(json["children"][0]["object"], "extract")
        os.unlink(args[0])
        path_manifest1 = settings.BASE_DIR / "fixtures" / "tuto" / "big_tuto_v1" / "manifest.json"
        path_manifest2 = settings.BASE_DIR / "fixtures" / "tuto" / "big_tuto_v1" / "manifest2.json"
        args = [str(path_manifest2)]
        shutil.copy(path_manifest1, path_manifest2)
        call_command("upgrade_manifest_to_v2", *args, **opts)
        manifest = path_manifest2.open("r")
        json = json_handler.loads(manifest.read())
        os.unlink(args[0])
        self.assertTrue("version" in json)
        self.assertTrue("licence" in json)
        self.assertTrue("children" in json)
        self.assertEqual(len(json["children"]), 5)
        self.assertEqual(json["children"][0]["object"], "container")
        self.assertEqual(len(json["children"][0]["children"]), 3)
        self.assertEqual(len(json["children"][0]["children"][0]["children"]),
                         3)
        path_manifest1 = settings.BASE_DIR / "fixtures" / "tuto" / "article_v1" / "manifest.json"
        path_manifest2 = settings.BASE_DIR / "fixtures" / "tuto" / "article_v1" / "manifest2.json"
        args = [path_manifest2]
        shutil.copy(path_manifest1, path_manifest2)
        call_command("upgrade_manifest_to_v2", *args, **opts)
        manifest = path_manifest2.open("r")
        json = json_handler.loads(manifest.read())

        self.assertTrue("version" in json)
        self.assertTrue("licence" in json)
        self.assertTrue("children" in json)
        self.assertEqual(len(json["children"]), 1)
        os.unlink(args[0])

    def test_generate_markdown(self):
        tuto = PublishedContentFactory(
            type="TUTORIAL")  # generate and publish a tutorial
        published = PublishedContent.objects.get(content_pk=tuto.pk)

        tuto2 = PublishedContentFactory(
            type="TUTORIAL")  # generate and publish a second tutorial
        published2 = PublishedContent.objects.get(content_pk=tuto2.pk)

        self.assertTrue(published.has_md())
        self.assertTrue(published2.has_md())
        os.remove(
            str(
                Path(published.get_extra_contents_directory(),
                     published.content_public_slug + ".md")))
        os.remove(
            str(
                Path(published2.get_extra_contents_directory(),
                     published2.content_public_slug + ".md")))
        self.assertFalse(published.has_md())
        self.assertFalse(published2.has_md())
        # test command with param
        call_command("generate_markdown", published.content.pk)
        self.assertTrue(published.has_md())
        self.assertFalse(published2.has_md())
        os.remove(
            str(
                Path(published.get_extra_contents_directory(),
                     published.content_public_slug + ".md")))
        # test command without param
        call_command("generate_markdown")
        self.assertTrue(published.has_md())
        self.assertTrue(published2.has_md())

    def test_generate_pdf(self):
        """ensure the behavior of the `python manage.py generate_pdf` commmand"""

        self.overridden_zds_app["content"][
            "build_pdf_when_published"] = True  # this test need PDF build, if any

        tuto = PublishedContentFactory(
            type="TUTORIAL")  # generate and publish a tutorial
        published = PublishedContent.objects.get(content_pk=tuto.pk)

        tuto2 = PublishedContentFactory(
            type="TUTORIAL")  # generate and publish a second tutorial
        published2 = PublishedContent.objects.get(content_pk=tuto2.pk)

        # ensure that PDF exists in the first place
        self.assertTrue(published.has_pdf())
        self.assertTrue(published2.has_pdf())

        pdf_path = os.path.join(published.get_extra_contents_directory(),
                                published.content_public_slug + ".pdf")
        pdf_path2 = os.path.join(published2.get_extra_contents_directory(),
                                 published2.content_public_slug + ".pdf")
        self.assertTrue(os.path.exists(pdf_path))
        self.assertTrue(os.path.exists(pdf_path2))

        # 1. re-generate (all) PDFs
        os.remove(pdf_path)
        os.remove(pdf_path2)
        self.assertFalse(os.path.exists(pdf_path))
        self.assertFalse(os.path.exists(pdf_path2))
        call_command("generate_pdf")
        self.assertTrue(os.path.exists(pdf_path))
        self.assertTrue(os.path.exists(pdf_path2))  # both PDFs are generated

        # 2. re-generate a given PDF
        os.remove(pdf_path)
        os.remove(pdf_path2)
        self.assertFalse(os.path.exists(pdf_path))
        self.assertFalse(os.path.exists(pdf_path2))
        call_command("generate_pdf", f"id={tuto.pk}")
        self.assertTrue(os.path.exists(pdf_path))
        self.assertFalse(
            os.path.exists(pdf_path2))  # only the first PDF is generated

        # 3. re-generate a given PDF with a wrong id
        os.remove(pdf_path)
        self.assertFalse(os.path.exists(pdf_path))
        self.assertFalse(os.path.exists(pdf_path2))
        call_command("generate_pdf", "id=-1")  # There is no content with pk=-1
        self.assertFalse(os.path.exists(pdf_path))
        self.assertFalse(os.path.exists(pdf_path2))  # so no PDF is generated !

    def test_last_participation_is_old(self):
        article = PublishedContentFactory(author_list=[self.user_author],
                                          type="ARTICLE")
        new_user = ProfileFactory().user
        reac = ContentReaction(author=self.user_author,
                               position=1,
                               related_content=article)
        reac.update_content("I will find you.")
        reac.save()
        article.last_note = reac
        article.save()

        self.assertFalse(last_participation_is_old(article, new_user))
        ContentRead(user=self.user_author, note=reac, content=article).save()
        reac = ContentReaction(author=new_user,
                               position=2,
                               related_content=article)
        reac.update_content("I will find you.")
        reac.save()
        article.last_note = reac
        article.save()
        ContentRead(user=new_user, note=reac, content=article).save()
        self.assertFalse(last_participation_is_old(article, new_user))
        self.assertTrue(last_participation_is_old(article, self.user_author))

    def testParseBadManifest(self):
        base_content = PublishableContentFactory(
            author_list=[self.user_author])
        versioned = base_content.load_version()
        versioned.add_container(Container("un peu plus près de 42"))
        versioned.dump_json()
        manifest = os.path.join(versioned.get_path(), "manifest.json")
        dictionary = json_handler.load(open(manifest))

        old_title = dictionary["title"]

        # first bad title
        dictionary["title"] = 81 * ["a"]
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )
        dictionary["title"] = "".join(dictionary["title"])
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )
        dictionary["title"] = "..."
        self.assertRaises(
            InvalidSlugError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )

        dictionary["title"] = old_title
        dictionary["children"][0]["title"] = 81 * ["a"]
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )

        dictionary["children"][0]["title"] = "bla"
        dictionary["children"][0]["slug"] = "..."
        self.assertRaises(
            InvalidSlugError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )

    def test_get_commit_author(self):
        """Ensure the behavior of `get_commit_author()` :
          - `git.Actor` use the pk of the bot account when no one is connected
          - `git.Actor` use the pk (and the email) of the connected account when available

        (Implementation of `git.Actor` is there :
        https://github.com/gitpython-developers/GitPython/blob/master/git/util.py#L312)
        """

        # 1. With user connected
        self.client.force_login(self.user_author)

        # go to whatever page, if not, `get_current_user()` does not work at all
        result = self.client.get(reverse("pages-index"))
        self.assertEqual(result.status_code, 200)

        actor = get_commit_author()
        self.assertEqual(actor["committer"].name, str(self.user_author.pk))
        self.assertEqual(actor["author"].name, str(self.user_author.pk))
        self.assertEqual(actor["committer"].email, self.user_author.email)
        self.assertEqual(actor["author"].email, self.user_author.email)

    def test_get_commit_author_not_auth(self):
        result = self.client.get(reverse("pages-index"))
        self.assertEqual(result.status_code, 200)

        actor = get_commit_author()
        self.assertEqual(actor["committer"].name, str(self.mas.pk))
        self.assertEqual(actor["author"].name, str(self.mas.pk))

    def invalid_slug_is_invalid(self):
        """ensure that an exception is raised when it should"""

        # exception are raised when title are invalid
        invalid_titles = [
            "-", "_", "__", "-_-", "$", "@", "&", "{}", "    ", "..."
        ]

        for t in invalid_titles:
            self.assertRaises(InvalidSlugError, slugify_raise_on_invalid, t)

        # Those slugs are recognized as wrong slug
        invalid_slugs = [
            "",  # empty
            "----",  # empty
            "___",  # empty
            "-_-",  # empty (!)
            "&;",  # invalid characters
            "!{",  # invalid characters
            "@",  # invalid character
            "a ",  # space !
        ]

        for s in invalid_slugs:
            self.assertFalse(check_slug(s))

        # too long slugs are forbidden :
        too_damn_long_slug = "a" * (
            self.overridden_zds_app["content"]["maximum_slug_size"] + 1)
        self.assertFalse(check_slug(too_damn_long_slug))

    def test_adjust_char_count(self):
        """Test the `adjust_char_count` command"""

        article = PublishedContentFactory(type="ARTICLE",
                                          author_list=[self.user_author])
        published = PublishedContent.objects.filter(content=article).first()
        published.char_count = None
        published.save()

        call_command("adjust_char_count")

        published = PublishedContent.objects.get(pk=published.pk)
        self.assertEqual(published.char_count, published.get_char_count())

    def test_image_with_non_ascii_chars(self):
        """seen on #4144"""
        article = PublishableContentFactory(type="article",
                                            author_list=[self.user_author])
        image_string = (
            "![Portrait de Richard Stallman en 2014. [Source](https://commons.wikimedia.org/wiki/"
            "File:Richard_Stallman_-_Fête_de_l%27Humanité_2014_-_010.jpg).]"
            "(/media/galleries/4410/c1016bf1-a1de-48a1-9ef1-144308e8725d.jpg)")
        article.sha_draft = article.load_version().repo_update(
            article.title, image_string, "", update_slug=False)
        article.save()
        publish_content(article, article.load_version())
        self.assertTrue(
            PublishedContent.objects.filter(content_id=article.pk).exists())

    def test_no_alert_on_unpublish(self):
        """related to #4860"""
        published = PublishedContentFactory(type="OPINION",
                                            author_list=[self.user_author])
        reaction = ContentReactionFactory(related_content=published,
                                          author=ProfileFactory().user,
                                          position=1,
                                          pubdate=datetime.datetime.now())
        Alert.objects.create(
            scope="CONTENT",
            comment=reaction,
            text="a text",
            author=ProfileFactory().user,
            pubdate=datetime.datetime.now(),
            content=published,
        )
        staff = StaffProfileFactory().user
        self.assertEqual(1, get_header_notifications(staff)["alerts"]["total"])
        unpublish_content(published, staff)
        self.assertEqual(0, get_header_notifications(staff)["alerts"]["total"])

    def tearDown(self):
        super().tearDown()
        PublicatorRegistry.registry = self.old_registry
예제 #28
0
    def testParseBadManifest(self):
        base_content = PublishableContentFactory(
            author_list=[self.user_author])
        versioned = base_content.load_version()
        versioned.add_container(Container("un peu plus près de 42"))
        versioned.dump_json()
        manifest = os.path.join(versioned.get_path(), "manifest.json")
        dictionary = json_handler.load(open(manifest))

        old_title = dictionary["title"]

        # first bad title
        dictionary["title"] = 81 * ["a"]
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )
        dictionary["title"] = "".join(dictionary["title"])
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )
        dictionary["title"] = "..."
        self.assertRaises(
            InvalidSlugError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )

        dictionary["title"] = old_title
        dictionary["children"][0]["title"] = 81 * ["a"]
        self.assertRaises(
            BadManifestError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )

        dictionary["children"][0]["title"] = "bla"
        dictionary["children"][0]["slug"] = "..."
        self.assertRaises(
            InvalidSlugError,
            get_content_from_json,
            dictionary,
            None,
            "",
            max_title_len=PublishableContent._meta.get_field(
                "title").max_length,
        )
예제 #29
0
class NotificationPublishableContentTest(TestCase):
    def setUp(self):
        self.user1 = ProfileFactory().user
        self.user2 = ProfileFactory().user

        # create a tutorial
        self.tuto = PublishableContentFactory(type="TUTORIAL")
        self.tuto.authors.add(self.user1)
        UserGalleryFactory(gallery=self.tuto.gallery,
                           user=self.user1,
                           mode="W")
        self.tuto.licence = LicenceFactory()
        self.tuto.subcategory.add(SubCategoryFactory())
        self.tuto.save()
        tuto_draft = self.tuto.load_version()

        # then, publish it !
        version = tuto_draft.current_version
        self.published = publish_content(self.tuto,
                                         tuto_draft,
                                         is_major_update=True)

        self.tuto.sha_public = version
        self.tuto.sha_draft = version
        self.tuto.public_version = self.published
        self.tuto.save()

        self.client.force_login(self.user1)

    def test_follow_content_at_publication(self):
        """
        When a content is published, authors automatically follow it.
        """
        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertIsNone(subscription)

        # Signal call by the view at the publication.
        signals.content_published.send(sender=self.tuto.__class__,
                                       instance=self.tuto,
                                       by_email=False)

        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertTrue(subscription.is_active)

    def test_follow_content_from_view(self):
        """
        Allows a user to follow (or not) a content from the view.
        """
        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertIsNone(subscription)

        result = self.client.post(
            reverse("content:follow-reactions", args=[self.tuto.pk]),
            {"follow": 1})
        self.assertEqual(result.status_code, 302)

        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertTrue(subscription.is_active)
        result = self.client.post(
            reverse("content:follow-reactions", args=[self.tuto.pk]),
            {"follow": 0})
        self.assertEqual(result.status_code, 302)
        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertFalse(subscription.is_active)

    def test_answer_subscription(self):
        """
        When a user posts on a publishable content, the user gets subscribed.
        """
        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertIsNone(subscription)

        result = self.client.post(
            reverse("content:add-reaction") + f"?pk={self.tuto.pk}",
            {
                "text": "message",
                "last_note": "0"
            },
            follow=True,
        )
        self.assertEqual(result.status_code, 200)

        subscription = ContentReactionAnswerSubscription.objects.get_existing(
            user=self.user1, content_object=self.tuto)
        self.assertTrue(subscription.is_active)

    def test_notification_read(self):
        """
        When the notification is a reaction, it is marked as read
        when the corresponding content is displayed to the user.
        """
        ContentReactionFactory(related_content=self.tuto,
                               author=self.user1,
                               position=1)
        last_note = ContentReactionFactory(related_content=self.tuto,
                                           author=self.user2,
                                           position=2)
        self.tuto.last_note = last_note
        self.tuto.save()

        notification = Notification.objects.get(subscription__user=self.user1)
        self.assertFalse(notification.is_read)

        result = self.client.get(reverse("tutorial:view",
                                         args=[self.tuto.pk, self.tuto.slug]),
                                 follow=False)
        self.assertEqual(result.status_code, 200)

        notification = Notification.objects.get(subscription__user=self.user1)
        self.assertTrue(notification.is_read)

    def test_subscription_to_new_publications_from_user(self):
        """
        Any user may subscribe to new publications from a user.
        """
        result = self.client.post(reverse("content:follow",
                                          args=[self.user1.pk]),
                                  follow=False)
        self.assertEqual(result.status_code, 403)

        self.client.logout()
        self.client.force_login(self.user2)

        result = self.client.post(
            reverse("content:follow", args=[self.user1.pk]),
            {"follow": 1},
            follow=False,
            HTTP_X_REQUESTED_WITH="XMLHttpRequest",
        )
        self.assertEqual(result.status_code, 200)

        subscription = NewPublicationSubscription.objects.get_existing(
            user=self.user2, content_object=self.user1)
        self.assertTrue(subscription.is_active)

        result = self.client.post(
            reverse("content:follow", args=[self.user1.pk]),
            {"email": 1},
            follow=False,
            HTTP_X_REQUESTED_WITH="XMLHttpRequest",
        )
        self.assertEqual(result.status_code, 200)

        subscription = NewPublicationSubscription.objects.get_existing(
            user=self.user2, content_object=self.user1)
        self.assertTrue(subscription.is_active)
        self.assertTrue(subscription.by_email)

    def test_notification_generated_when_a_tuto_is_published(self):
        """
        When a user subscribe to new publications from a user, a notification is generated when a publication is
        published.
        """
        subscription = NewPublicationSubscription.objects.toggle_follow(
            self.user1, self.user2)

        signals.content_published.send(sender=self.tuto.__class__,
                                       instance=self.tuto,
                                       by_email=False)

        notifications = Notification.objects.filter(subscription=subscription,
                                                    is_read=False).all()
        self.assertEqual(1, len(notifications))

        signals.content_read.send(sender=self.tuto.__class__,
                                  instance=self.tuto,
                                  user=self.user2,
                                  target=ContentReaction)

        notifications = Notification.objects.filter(subscription=subscription,
                                                    is_read=False).all()
        self.assertEqual(1, len(notifications))

        signals.content_read.send(sender=self.tuto.__class__,
                                  instance=self.tuto,
                                  user=self.user2,
                                  target=PublishableContent)

        notifications = Notification.objects.filter(subscription=subscription,
                                                    is_read=False).all()
        self.assertEqual(0, len(notifications))

    def test_no_error_on_multiple_subscription(self):
        subscription = NewPublicationSubscription.objects.toggle_follow(
            self.user1, self.user2)

        signals.content_published.send(sender=self.tuto.__class__,
                                       instance=self.tuto,
                                       by_email=False)

        subscription1 = Notification.objects.filter(subscription=subscription,
                                                    is_read=False).first()
        subscription2 = copy.copy(subscription1)
        subscription2.save()
        subscription.mark_notification_read(self.tuto)
        subscription1 = Notification.objects.filter(subscription=subscription,
                                                    is_read=False).first()
        self.assertIsNone(subscription1)
        self.assertEqual(
            1,
            Notification.objects.filter(subscription=subscription,
                                        is_read=True).count())
예제 #30
0
class PublicationFronttest(StaticLiveServerTestCase, TutorialTestMixin,
                           TutorialFrontMixin):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        options = Options()
        options.headless = True
        cls.selenium = Firefox(options=options)
        cls.selenium.implicitly_wait(10)

    @classmethod
    def tearDownClass(cls):
        cls.selenium.quit()
        super().tearDownClass()

    def tearDown(self):
        super().tearDown()
        self.clean_media_dir()

    def setUp(self):
        self.overridden_zds_app = overridden_zds_app
        # don't build PDF to speed up the tests
        overridden_zds_app["content"]["build_pdf_when_published"] = False

        self.staff = StaffProfileFactory().user

        settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
        self.mas = ProfileFactory().user
        overridden_zds_app["member"]["bot_account"] = self.mas.username

        self.licence = LicenceFactory()
        self.subcategory = SubCategoryFactory(category=CategoryFactory())

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().user
        self.content = PublishableContentFactory(
            author_list=[self.user_author], light=False)
        self.part_published = ContainerFactory(
            db_object=self.content,
            light=False,
            parent=self.content.load_version())
        self.ignored_part = ContainerFactory(
            db_object=self.content,
            light=False,
            parent=self.content.load_version())
        ExtractFactory(db_object=self.content,
                       container=self.part_published,
                       light=False)
        ExtractFactory(db_object=self.content,
                       container=self.ignored_part,
                       light=False)

    def test_partial_publication(self):
        self.login_author()
        self.selenium.get(self.live_server_url +
                          self.ignored_part.get_absolute_url())
        find_element = self.selenium.find_element_by_css_selector
        button = WebDriverWait(self.selenium, 20).until(
            expected_conditions.element_to_be_clickable(
                (By.CSS_SELECTOR, ".readiness")))
        readiness = button.get_attribute("data-is-ready")
        button.click()
        self.wait_element_attribute_change((By.CSS_SELECTOR, ".readiness"),
                                           "data-is-ready", readiness, 20)
        self.content = PublishableContent.objects.get(pk=self.content.pk)
        self.ignored_part = self.content.load_version().children[1]
        self.assertFalse(self.ignored_part.ready_to_publish,
                         "part should be marked as not ready to publish")
        self.selenium.get(self.live_server_url +
                          self.content.get_absolute_url())
        self.selenium.get(self.live_server_url +
                          self.ignored_part.get_absolute_url())
        button = find_element(".readiness")
        self.assertNotEqual(readiness, button.get_attribute("data-is-ready"),
                            "part should be marked as not ready to publish")
        self.selenium.get(self.live_server_url +
                          self.content.get_absolute_url())
        self.ask_validation()
        self.logout()
        self.login_staff()
        self.take_reservation()
        self.validate()
        url = PublishedContent.objects.get(
            content__pk=self.content.pk).get_absolute_url_online()
        self.selenium.get(self.live_server_url + url)
        self.assertRaises(
            WebDriverException,
            find_element,
            'a[href="{}"]'.format(
                reverse(
                    "tutorial:view-container",
                    kwargs={
                        "slug": self.content.slug,
                        "pk": self.content.pk,
                        "container_slug": self.ignored_part.slug
                    },
                )),
        )

    def test_collaborative_article_edition_and_editor_persistence(self):
        selenium = self.selenium
        find_element = selenium.find_element_by_css_selector

        author = ProfileFactory()

        article = PublishableContentFactory(type="ARTICLE",
                                            author_list=[author.user])

        versioned_article = article.load_version()
        article.sha_draft = versioned_article.repo_update("article",
                                                          "",
                                                          "",
                                                          update_slug=False)
        article.save()

        article_edit_url = reverse("content:edit",
                                   args=[article.pk, article.slug])

        self.login(author)
        selenium.execute_script('localStorage.setItem("editor_choice", "new")'
                                )  # we want the new editor
        selenium.get(self.live_server_url + article_edit_url)

        intro = find_element("div#div_id_introduction div.CodeMirror")
        # ActionChains: Support for CodeMirror https://stackoverflow.com/a/48969245/2226755
        action_chains = ActionChains(selenium)
        scrollDriverTo(selenium, 0, 312)
        action_chains.click(intro).perform()
        action_chains.send_keys("intro").perform()

        output = "div#div_id_introduction div.CodeMirror div.CodeMirror-code"
        self.assertEqual("intro", find_element(output).text)

        article.sha_draft = versioned_article.repo_update("article",
                                                          "new intro",
                                                          "",
                                                          update_slug=False)
        article.save()

        selenium.refresh()

        self.assertEqual(
            "new intro",
            find_element(".md-editor#id_introduction").get_attribute("value"))

    def test_the_editor_forgets_its_content_on_form_submission(self):
        selenium = self.selenium
        find_element = selenium.find_element_by_css_selector

        author = ProfileFactory()

        self.login(author)
        selenium.execute_script('localStorage.setItem("editor_choice", "new")'
                                )  # we want the new editor
        new_article_url = self.live_server_url + reverse(
            "content:create-article")
        selenium.get(new_article_url)
        WebDriverWait(self.selenium, 10).until(
            ec.element_to_be_clickable(
                (By.CSS_SELECTOR,
                 "input[type=checkbox][name=subcategory]"))).click()

        find_element("#id_title").send_keys("Oulipo")

        intro = find_element("div#div_id_introduction div.CodeMirror")
        action_chains = ActionChains(selenium)
        action_chains.click(intro).perform()
        action_chains.send_keys(
            "Le cadavre exquis boira le vin nouveau.").perform()

        find_element(".content-container button[type=submit]").click()

        self.assertTrue(
            WebDriverWait(selenium, 10).until(ec.title_contains("Oulipo")))

        selenium.get(new_article_url)

        self.assertEqual(
            "",
            find_element(".md-editor#id_introduction").get_attribute("value"))