Beispiel #1
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)
    def test_opinion_publication_guest(self):
        """
        Test the publication of PublishableContent where type is OPINION (with guest => 403).
        """

        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.assertEqual(
            self.client.login(
                username=self.user_guest.username,
                password='******'),
            True)

        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, 403)

        self.assertEqual(PublishedContent.objects.count(), 0)
Beispiel #3
0
    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
Beispiel #4
0
    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_objet=bigtuto)
        chapter1 = ContainerFactory(parent=part1, db_objet=bigtuto)
        ExtractFactory(container=chapter1, db_object=bigtuto)
        part2 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto)
        chapter2 = ContainerFactory(parent=part2, db_objet=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)
Beispiel #5
0
 def test_get_tuto_count(self):
     # Start with 0
     self.assertEqual(self.user1.get_tuto_count(), 0)
     # Create Tuto !
     minituto = PublishableContentFactory(type='TUTORIAL')
     minituto.authors.add(self.user1.user)
     minituto.gallery = GalleryFactory()
     minituto.save()
     # Should be 1
     self.assertEqual(self.user1.get_tuto_count(), 1)
Beispiel #6
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(force_slug_update=False)
     publish_content(article, article.load_version())
     self.assertTrue(PublishedContent.objects.filter(content_id=article.pk).exists())
Beispiel #7
0
 def test_get_validate_tutos(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_validate_tutos()), 0)
     # Create Tuto !
     validatetuto = PublishableContentFactory(type='TUTORIAL', author_list=[self.user1.user])
     validatetuto.sha_validation = 'whatever'
     validatetuto.save()
     # Should be 1
     validatetutos = self.user1.get_validate_tutos()
     self.assertEqual(len(validatetutos), 1)
     self.assertEqual(validatetuto, validatetutos[0])
Beispiel #8
0
 def test_get_draft_articles(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_draft_articles()), 0)
     # Create article !
     article = PublishableContentFactory(type='ARTICLE')
     article.authors.add(self.user1.user)
     article.save()
     # Should be 1
     articles = self.user1.get_draft_articles()
     self.assertEqual(len(articles), 1)
     self.assertEqual(article, articles[0])
Beispiel #9
0
 def test_get_draft_tutos(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_draft_tutos()), 0)
     # Create Tuto !
     drafttuto = PublishableContentFactory(type='TUTORIAL')
     drafttuto.authors.add(self.user1.user)
     drafttuto.gallery = GalleryFactory()
     drafttuto.save()
     # Should be 1
     drafttutos = self.user1.get_draft_tutos()
     self.assertEqual(len(drafttutos), 1)
     self.assertEqual(drafttuto, drafttutos[0])
Beispiel #10
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)
Beispiel #11
0
 def test_get_beta_tutos(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_beta_tutos()), 0)
     # Create Tuto !
     betatetuto = PublishableContentFactory(type='TUTORIAL')
     betatetuto.authors.add(self.user1.user)
     betatetuto.gallery = GalleryFactory()
     betatetuto.sha_beta = 'whatever'
     betatetuto.save()
     # Should be 1
     betatetutos = self.user1.get_beta_tutos()
     self.assertEqual(len(betatetutos), 1)
     self.assertEqual(betatetuto, betatetutos[0])
Beispiel #12
0
 def test_get_public_tutos(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_public_tutos()), 0)
     # Create Tuto !
     publictuto = PublishableContentFactory(type='TUTORIAL')
     publictuto.authors.add(self.user1.user)
     publictuto.gallery = GalleryFactory()
     publictuto.sha_public = "whatever"
     publictuto.save()
     # Should be 0 because publication was not used
     publictutos = self.user1.get_public_tutos()
     self.assertEqual(len(publictutos), 0)
     PublishedContentFactory(author_list=[self.user1.user])
     self.assertEqual(len(self.user1.get_public_tutos()), 1)
Beispiel #13
0
 def test_get_public_articles(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_public_articles()), 0)
     # Create article !
     article = PublishableContentFactory(type='ARTICLE')
     article.authors.add(self.user1.user)
     article.sha_public = 'whatever'
     article.save()
     # Should be 0
     articles = self.user1.get_public_articles()
     self.assertEqual(len(articles), 0)
     # Should be 1
     PublishedContentFactory(author_list=[self.user1.user], type="Article")
     self.assertEqual(len(self.user1.get_public_tutos()), 1)
Beispiel #14
0
 def test_get_public_tutos(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_public_tutos()), 0)
     # Create Tuto !
     publictuto = PublishableContentFactory(type='TUTORIAL')
     publictuto.authors.add(self.user1.user)
     publictuto.gallery = GalleryFactory()
     publictuto.sha_public = 'whatever'
     publictuto.save()
     # Should be 0 because publication was not used
     publictutos = self.user1.get_public_tutos()
     self.assertEqual(len(publictutos), 0)
     PublishedContentFactory(author_list=[self.user1.user])
     self.assertEqual(len(self.user1.get_public_tutos()), 1)
Beispiel #15
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())
Beispiel #16
0
 def test_get_public_articles(self):
     # Start with 0
     self.assertEqual(len(self.user1.get_public_articles()), 0)
     # Create article !
     article = PublishableContentFactory(type='ARTICLE')
     article.authors.add(self.user1.user)
     article.sha_public = 'whatever'
     article.save()
     # Should be 0
     articles = self.user1.get_public_articles()
     self.assertEqual(len(articles), 0)
     # Should be 1
     PublishedContentFactory(author_list=[self.user1.user], type='ARTICLE')
     self.assertEqual(len(self.user1.get_public_articles()), 1)
     self.assertEqual(len(self.user1.get_public_tutos()), 0)
Beispiel #17
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
Beispiel #18
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"))
Beispiel #19
0
    def test_opinion_publication_author(self):
        """
        Test the publication of PublishableContent where type is OPINION (with author).
        """

        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.assertEqual(
            self.client.login(username=self.user_author.username,
                              password="******"), True)

        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)
Beispiel #20
0
class ContentNotification(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.assertTrue(
            self.client.login(username=self.user1.username,
                              password='******'))

    def test_no_persistant_notif_on_revoke(self):
        from zds.tutorialv2.publication_utils import unpublish_content
        NewPublicationSubscription.objects.get_or_create_active(
            self.user1, self.user2)
        content = PublishedContentFactory(author_list=[self.user2])

        notif_signals.new_content.send(sender=self.tuto.__class__,
                                       instance=content,
                                       by_email=False)
        self.assertEqual(
            1, len(Notification.objects.get_notifications_of(self.user1)))
        unpublish_content(content)
        self.assertEqual(
            0, len(Notification.objects.get_notifications_of(self.user1)))
Beispiel #21
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)
Beispiel #22
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_objet=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_objet=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)
Beispiel #23
0
    def test_opinion_publication_author(self):
        """
        Test the publication of PublishableContent where type is OPINION (with author).
        """

        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.assertEqual(
            self.client.login(username=self.user_author.username,
                              password='******'), True)

        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)
Beispiel #24
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.get(self.live_server_url + article_edit_url)

        intro = find_element('.md-editor#id_introduction')
        intro.send_keys('intro')

        selenium.refresh()

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

        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'))
Beispiel #25
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)
Beispiel #26
0
    def test_opinion_publication_guest(self):
        """
        Test the publication of PublishableContent where type is OPINION (with guest => 403).
        """

        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_guest)

        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, 403)

        self.assertEqual(PublishedContent.objects.count(), 0)
Beispiel #27
0
class InterventionsTest(TestCase):
    """
    This test uses quite complicated paths to check number of notifications:
    1. Create private topics and do stuff with them
    2. User signs in
    3. Render the home page
    4. Check the number of unread private messages on home page source code
    This because a correct test of this function requires a complete context (or it behaves strangely)
    """

    def setUp(self):
        self.licence = LicenceFactory()
        self.subcategory = SubCategoryFactory()

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

        self.tuto = PublishableContentFactory(type="TUTORIAL")
        self.tuto.authors.add(self.author.user)
        self.tuto.licence = self.licence
        self.tuto.subcategory.add(self.subcategory)
        self.tuto.save()

        self.validation = Validation(
            content=self.tuto,
            version=self.tuto.sha_draft,
            comment_authors="bla",
            date_proposition=datetime.now(),
        )
        self.validation.save()

        self.topic = send_mp(author=self.author.user, users=[], title="Title", text="Testing", subtitle="", leave=False)
        self.topic.add_participant(self.user.user)
        send_message_mp(self.user.user, self.topic, "Testing")

        # humane_delta test
        periods = ((1, 0), (2, 1), (3, 7), (4, 30), (5, 360))
        cont = dict()
        cont["date_today"] = periods[0][0]
        cont["date_yesterday"] = periods[1][0]
        cont["date_last_week"] = periods[2][0]
        cont["date_last_month"] = periods[3][0]
        cont["date_last_year"] = periods[4][0]
        self.context = Context(cont)

    def test_interventions_privatetopics(self):

        self.client.force_login(self.author.user)
        response = self.client.post(reverse("homepage"))
        self.assertEqual(200, response.status_code)
        self.assertContains(response, '<span class="notif-count">1</span>', html=True)

        self.client.logout()

        self.client.force_login(self.user.user)
        response = self.client.post(reverse("homepage"))
        self.assertEqual(200, response.status_code)
        self.assertContains(response, '<span class="notif-count">1</span>', html=True)

    def test_interventions_privatetopics_author_leave(self):

        # profile1 (author) leave topic
        move = self.topic.participants.first()
        self.topic.author = move
        self.topic.participants.remove(move)
        self.topic.save()

        self.client.force_login(self.user.user)
        response = self.client.post(reverse("homepage"))
        self.assertEqual(200, response.status_code)
        self.assertContains(response, '<span class="notif-count">1</span>', html=True)

    def test_interventions_waiting_contents(self):
        # Login as staff
        self.client.force_login(self.staff.user)

        # check that the number of waiting tutorials is correct
        response = self.client.post(reverse("homepage"))
        self.assertEqual(200, response.status_code)
        self.assertContains(response, "(1 tutoriel)")

        # Mark the content as reserved
        self.validation.status = "PENDING_V"
        self.validation.save()

        # and check that the count was removed
        response = self.client.post(reverse("homepage"))
        self.assertEqual(200, response.status_code)
        self.assertNotContains(response, "(1 tutoriel)")

    def test_interventions_humane_delta(self):
        tr = Template("{% load interventions %}" "{{ date_today|humane_delta }}").render(self.context)
        self.assertEqual(escape("Aujourd'hui"), tr)

        tr = Template("{% load interventions %}" "{{ date_yesterday|humane_delta }}").render(self.context)
        self.assertEqual("Hier", tr)

        tr = Template("{% load interventions %}" "{{ date_last_week|humane_delta }}").render(self.context)
        self.assertEqual("Les 7 derniers jours", tr)

        tr = Template("{% load interventions %}" "{{ date_last_month|humane_delta }}").render(self.context)
        self.assertEqual("Les 30 derniers jours", tr)

        tr = Template("{% load interventions %}" "{{ date_last_year|humane_delta }}").render(self.context)
        self.assertEqual("Plus ancien", tr)
Beispiel #28
0
class EditContentLicenseFunctionalTests(TutorialTestMixin, TestCase):
    """Test the detailed behavior of the feature, such as updates of the database or repositories."""
    def setUp(self):
        # Create a user
        self.author = ProfileFactory()

        # Create licenses
        self.license_1 = LicenceFactory()
        self.license_2 = LicenceFactory()

        # Create a content
        self.content = PublishableContentFactory(
            author_list=[self.author.user], add_license=False)

        # Get information to be reused in tests
        self.form_url = reverse('content:edit-license',
                                kwargs={'pk': self.content.pk})

        # Log in with an authorized user (e.g the author of the content) to perform the tests
        login_success = self.client.login(username=self.author.user.username,
                                          password='******')
        self.assertTrue(login_success)

    def test_form_function(self):
        """Test many use cases for the form."""
        test_cases = self.get_test_cases()
        for case_name, case in test_cases.items():
            with self.subTest(msg=case_name):
                self.enforce_preconditions(case['preconditions'])
                self.post_form(case['inputs'])
                self.check_effects(case['expected_outputs'])

    def get_test_cases(self):
        """List test cases for the license editing form."""
        return {
            'from blank to license 1, no preference, no udpate of preferences':
            {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_1,
                    'update_preferred_license': False
                },
                'expected_outputs': {
                    'content_license': self.license_1,
                    'preferred_license': None
                }
            },
            'from blank to license 1, no preference, udpate of preferences': {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_1,
                    'update_preferred_license': True
                },
                'expected_outputs': {
                    'content_license': self.license_1,
                    'preferred_license': self.license_1
                }
            },
            'from blank to license 2, no preference, no udpate of preferences':
            {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_2,
                    'update_preferred_license': False
                },
                'expected_outputs': {
                    'content_license': self.license_2,
                    'preferred_license': None
                }
            },
            'from blank to license 2, no preference, udpate of preferences': {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_2,
                    'update_preferred_license': True
                },
                'expected_outputs': {
                    'content_license': self.license_2,
                    'preferred_license': self.license_2
                }
            },
            'from blank to license 1, preference, no udpate of preferences': {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': self.license_2
                },
                'inputs': {
                    'license': self.license_1,
                    'update_preferred_license': False
                },
                'expected_outputs': {
                    'content_license': self.license_1,
                    'preferred_license': self.license_2
                }
            },
            'from blank to license 1, preference, udpate of preferences': {
                'preconditions': {
                    'content_license': None,
                    'preferred_license': self.license_2
                },
                'inputs': {
                    'license': self.license_1,
                    'update_preferred_license': True
                },
                'expected_outputs': {
                    'content_license': self.license_1,
                    'preferred_license': self.license_1
                }
            },
            'from license 1 to license 2, no preference, no udpate of preferences':
            {
                'preconditions': {
                    'content_license': self.license_1,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_2,
                    'update_preferred_license': False
                },
                'expected_outputs': {
                    'content_license': self.license_2,
                    'preferred_license': None
                }
            },
            'from license 1 to license 2, no preference, udpate of preferences':
            {
                'preconditions': {
                    'content_license': self.license_1,
                    'preferred_license': None
                },
                'inputs': {
                    'license': self.license_2,
                    'update_preferred_license': True
                },
                'expected_outputs': {
                    'content_license': self.license_2,
                    'preferred_license': self.license_2
                }
            },
        }

    def enforce_preconditions(self, preconditions):
        """Prepare the test environment to match given preconditions"""

        # Enforce preconditions for license in database
        self.content.licence = preconditions['content_license']
        self.content.save()
        self.assertEqual(self.content.licence,
                         preconditions['content_license'])

        # Enforce preconditions for license in repository
        versioned = self.content.load_version()
        versioned.licence = preconditions['content_license']
        sha = versioned.repo_update_top_container('Title', self.content.slug,
                                                  'introduction', 'conclusion')
        updated_versioned = self.content.load_version(sha)
        self.assertEqual(updated_versioned.licence,
                         preconditions['content_license'])

        # Enforce preconditions for preferred license
        self.author.licence = preconditions['preferred_license']
        self.author.save()
        updated_profile = Profile.objects.get(pk=self.author.pk)
        self.assertEqual(updated_profile.licence,
                         preconditions['preferred_license'])

    def post_form(self, inputs):
        """Post the form with given inputs."""
        form_data = {
            'license': inputs['license'].pk,
            'update_preferred_license': inputs['update_preferred_license']
        }
        self.client.post(self.form_url, form_data)

    def check_effects(self, expected_outputs):
        """Check the effects of having sent the form."""

        # Check updating of the database
        updated_content = PublishableContent.objects.get(pk=self.content.pk)
        updated_profile = Profile.objects.get(pk=self.author.pk)
        self.assertEqual(updated_content.licence,
                         expected_outputs['content_license'])
        self.assertEqual(updated_profile.licence,
                         expected_outputs['preferred_license'])

        # Check updating of the repository
        versioned = updated_content.load_version()
        self.assertEqual(versioned.licence,
                         expected_outputs['content_license'])
Beispiel #29
0
class ContentMoveTests(TestCase):

    def setUp(self):

        # don't build PDF to speed up the tests
        settings.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
        settings.ZDS_APP['member']['bot_account'] = self.mas.username

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

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().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.subcategory.add(self.subcategory)
        self.tuto.save()

        self.beta_forum = ForumFactory(
            pk=settings.ZDS_APP['forum']['beta_forum_id'],
            category=CategoryFactory(position=1),
            position_in_category=1)  # ensure that the forum, for the beta versions, is created

        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.extract1 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        bot = Group(name=settings.ZDS_APP['member']['bot_group'])
        bot.save()

    def test_move_up_extract(self):
        # login with author
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        self.extract2 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        old_sha = tuto.sha_draft
        # test moving up smoothly
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract2.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'up',
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children[0]
        self.assertEqual(self.extract2.slug, extract.slug)
        # test moving up the first element
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract2.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'up',
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug]\
            .children_dict[self.chapter1.slug].children_dict[self.extract2.slug]
        self.assertEqual(1, extract.position_in_parent)

        # test moving without permission

        self.client.logout()
        self.assertEqual(
            self.client.login(
                username=self.user_guest.username,
                password='******'),
            True)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract2.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'up',
                'pk': tuto.pk
            },
            follow=False)
        self.assertEqual(result.status_code, 403)

    def test_move_extract_before(self):
        # test 1 : move extract after a sibling
        # login with author
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        self.extract2 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        self.extract3 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        old_sha = tuto.sha_draft
        # test moving smoothly
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'before:' + self.extract3.get_path(True)[:-3],
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children[0]
        self.assertEqual(self.extract2.slug, extract.slug)

        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        # test changing parent for extract (smoothly)
        self.chapter2 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.extract4 = ExtractFactory(container=self.chapter2, db_object=self.tuto)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'before:' + self.extract4.get_full_slug(),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))
        # test changing parents on a 'midsize content' (i.e depth of 1)
        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)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': first_extract.slug,
                'container_slug': first_container.get_path(True),
                'first_level_slug': '',
                'moving_method': 'before:' + second_extract.get_full_slug(),
                'pk': midsize.pk
            },
            follow=True)
        self.assertEqual(result.status_code, 200)
        self.assertFalse(isfile(first_extract.get_path(True)))
        midsize = PublishableContent.objects.filter(pk=midsize.pk).first()
        midsize_draft = midsize.load_version()
        second_container_draft = midsize_draft.children[1]
        self.assertEqual(second_container_draft.children[0].title, first_extract.title)
        self.assertTrue(second_container_draft.children[0].get_path(False))

        # test try to move to a container that can't get extract
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter2.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'before:' + self.chapter1.get_path(True),
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))
        # test try to move near an extract that does not exist
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter2.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'before:' + self.chapter1.get_path(True) + '/un-mauvais-extrait',
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(404, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))

    def test_move_container_before(self):
        # login with author
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        self.chapter2 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.chapter3 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.part2 = ContainerFactory(parent=self.tuto_draft, db_object=self.tuto)
        self.chapter4 = ContainerFactory(parent=self.part2, db_object=self.tuto)
        self.extract5 = ExtractFactory(container=self.chapter3, db_object=self.tuto)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        # test changing parent for container (smoothly)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.chapter3.slug,
                'container_slug': self.part1.slug,
                'first_level_slug': '',
                'moving_method': 'before:' + self.chapter4.get_path(True),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        self.assertEqual(2, len(versioned.children_dict[self.part2.slug].children))

        chapter = versioned.children_dict[self.part2.slug].children[0]
        self.assertTrue(isdir(chapter.get_path()))
        self.assertEqual(1, len(chapter.children))
        self.assertTrue(isfile(chapter.children[0].get_path()))
        self.assertEqual(self.extract5.slug, chapter.children[0].slug)
        self.assertEqual(self.chapter3.slug, chapter.slug)
        chapter = versioned.children_dict[self.part2.slug].children[1]
        self.assertEqual(self.chapter4.slug, chapter.slug)
        # test changing parent for too deep container
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.part1.slug,
                'container_slug': self.tuto.slug,
                'first_level_slug': '',
                'moving_method': 'before:' + self.chapter4.get_path(True),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        self.assertEqual(2, len(versioned.children_dict[self.part2.slug].children))
        chapter = versioned.children_dict[self.part2.slug].children[0]
        self.assertEqual(self.chapter3.slug, chapter.slug)
        chapter = versioned.children_dict[self.part2.slug].children[1]
        self.assertEqual(self.chapter4.slug, chapter.slug)

        # test moving before the root
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.part1.slug,
                'container_slug': self.tuto.slug,
                'first_level_slug': '',
                'moving_method': 'before:' + self.tuto.load_version().get_path(),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(404, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        self.assertEqual(2, len(versioned.children_dict[self.part2.slug].children))
        chapter = versioned.children_dict[self.part2.slug].children[0]
        self.assertEqual(self.chapter3.slug, chapter.slug)
        chapter = versioned.children_dict[self.part2.slug].children[1]
        self.assertEqual(self.chapter4.slug, chapter.slug)

        # test moving without permission

        self.client.logout()
        self.assertEqual(
            self.client.login(
                username=self.user_guest.username,
                password='******'),
            True)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.chapter2.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'up',
                'pk': tuto.pk
            },
            follow=False)
        self.assertEqual(result.status_code, 403)

    def test_move_extract_after(self):
        # test 1 : move extract after a sibling
        # login with author
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        self.extract2 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        self.extract3 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        old_sha = tuto.sha_draft
        # test moving smoothly
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'after:' + self.extract3.get_path(True)[:-3],
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children[0]
        self.assertEqual(self.extract2.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children[1]
        self.assertEqual(self.extract3.slug, extract.slug)

        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        # test changing parent for extract (smoothly)
        self.chapter2 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.extract4 = ExtractFactory(container=self.chapter2, db_object=self.tuto)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter1.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'after:' + self.extract4.get_path(True)[:-3],
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))
        # test try to move to a container that can't get extract
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter2.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'after:' + self.chapter1.get_path(True),
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))
        # test try to move near an extract that does not exist
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.extract1.slug,
                'container_slug': self.chapter2.slug,
                'first_level_slug': self.part1.slug,
                'moving_method': 'after:' + self.chapter1.get_path(True) + '/un-mauvais-extrait',
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(404, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[1]
        self.assertEqual(self.extract1.slug, extract.slug)
        extract = versioned.children_dict[self.part1.slug].children_dict[self.chapter2.slug].children[0]
        self.assertEqual(self.extract4.slug, extract.slug)
        self.assertEqual(2, len(versioned.children_dict[self.part1.slug].children_dict[self.chapter1.slug].children))

    def test_move_container_after(self):
        # login with author
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        self.chapter2 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.chapter3 = ContainerFactory(parent=self.part1, db_object=self.tuto)
        self.part2 = ContainerFactory(parent=self.tuto_draft, db_object=self.tuto)
        self.extract5 = ExtractFactory(container=self.chapter3, db_object=self.tuto)
        self.chapter4 = ContainerFactory(parent=self.part2, db_object=self.tuto)
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        # test changing parent for container (smoothly)
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.chapter3.slug,
                'container_slug': self.part1.slug,
                'first_level_slug': '',
                'moving_method': 'after:' + self.chapter4.get_path(True),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertNotEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        self.assertEqual(2, len(versioned.children_dict[self.part2.slug].children))
        chapter = versioned.children_dict[self.part2.slug].children[1]
        self.assertEqual(1, len(chapter.children))
        self.assertTrue(isfile(chapter.children[0].get_path()))
        self.assertEqual(self.extract5.slug, chapter.children[0].slug)
        self.assertEqual(self.chapter3.slug, chapter.slug)
        chapter = versioned.children_dict[self.part2.slug].children[0]
        self.assertEqual(self.chapter4.slug, chapter.slug)
        # test changing parent for too deep container
        tuto = PublishableContent.objects.get(pk=self.tuto.pk)
        old_sha = tuto.sha_draft
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': self.part1.slug,
                'container_slug': self.tuto.slug,
                'first_level_slug': '',
                'moving_method': 'after:' + self.chapter4.get_path(True),
                'pk': tuto.pk
            },
            follow=True)

        self.assertEqual(200, result.status_code)
        self.assertEqual(old_sha, PublishableContent.objects.get(pk=tuto.pk).sha_draft)
        versioned = PublishableContent.objects.get(pk=tuto.pk).load_version()
        self.assertEqual(2, len(versioned.children_dict[self.part2.slug].children))
        chapter = versioned.children_dict[self.part2.slug].children[1]
        self.assertEqual(self.chapter3.slug, chapter.slug)
        chapter = versioned.children_dict[self.part2.slug].children[0]
        self.assertEqual(self.chapter4.slug, chapter.slug)

    def test_move_no_slug_update(self):
        """
        this test comes from issue #3328 (https://github.com/zestedesavoir/zds-site/issues/3328)
        telling it is tricky is kind of euphemism.
        :return:
        """
        LicenceFactory(code='CC BY')
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)
        draft_zip_path = join(dirname(__file__), 'fake_lasynchrone-et-le-multithread-en-net.zip')
        result = self.client.post(
            reverse('content:import-new'),
            {
                'archive': open(draft_zip_path),
                'subcategory': self.subcategory.pk
            },
            follow=False
        )
        self.assertEqual(result.status_code, 302)
        tuto = PublishableContent.objects.last()
        published = publish_content(tuto, tuto.load_version(), True)
        tuto.sha_public = tuto.sha_draft
        tuto.public_version = published
        tuto.save()
        extract1 = tuto.load_version().children[0]
        # test moving up smoothly
        result = self.client.post(
            reverse('content:move-element'),
            {
                'child_slug': extract1.slug,
                'first_level_slug': '',
                'container_slug': tuto.slug,
                'moving_method': 'down',
                'pk': tuto.pk
            },
            follow=True)
        self.assertEqual(200, result.status_code)
        self.assertTrue(isdir(tuto.get_repo_path()))

    def tearDown(self):
        if os.path.isdir(settings.ZDS_APP['content']['repo_private_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_private_path'])
        if os.path.isdir(settings.ZDS_APP['content']['repo_public_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_public_path'])
        if os.path.isdir(settings.MEDIA_ROOT):
            shutil.rmtree(settings.MEDIA_ROOT)

        # re-activate PDF build
        settings.ZDS_APP['content']['build_pdf_when_published'] = True
Beispiel #30
0
class ContentTests(TestCase):
    def setUp(self):

        # don't build PDF to speed up the tests
        settings.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
        settings.ZDS_APP['member']['bot_account'] = self.mas.username

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

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().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.subcategory.add(self.subcategory)
        self.tuto.save()

        self.beta_forum = ForumFactory(
            pk=settings.ZDS_APP['forum']['beta_forum_id'],
            category=CategoryFactory(position=1),
            position_in_category=1
        )  # ensure that the forum, for the beta versions, is created

        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.extract1 = ExtractFactory(container=self.chapter1,
                                       db_object=self.tuto)
        bot = Group(name=settings.ZDS_APP['member']['bot_group'])
        bot.save()
        self.external = UserFactory(
            username=settings.ZDS_APP['member']['external_account'],
            password='******')

    def test_public_lists(self):
        tutorial = PublishedContentFactory(author_list=[self.user_author])
        tutorial_unpublished = PublishableContentFactory(
            author_list=[self.user_author])
        article = PublishedContentFactory(author_list=[self.user_author],
                                          type='ARTICLE')
        article_unpublished = PublishableContentFactory(
            author_list=[self.user_author], type='ARTICLE')
        self.client.logout()
        resp = self.client.get(reverse('tutorial:list'))
        self.assertContains(resp, tutorial.title)
        self.assertNotContains(resp, tutorial_unpublished.title)
        resp = self.client.get(reverse('article:list'))
        self.assertContains(resp, article.title)
        self.assertNotContains(resp, article_unpublished.title)
        resp = self.client.get(
            reverse('content:find-tutorial', args=[self.user_author.pk]) +
            '?filter=public')
        self.assertContains(resp, tutorial.title)
        self.assertNotContains(resp, tutorial_unpublished.title)
        resp = self.client.get(
            reverse('content:find-tutorial', args=[self.user_author.pk]) +
            '?filter=redaction')
        self.assertEqual(resp.status_code, 403)
        resp = self.client.get(
            reverse('content:find-article', args=[self.user_author.pk]) +
            '?filter=public')
        self.assertContains(resp, article.title)
        self.assertNotContains(resp, article_unpublished.title)
        resp = self.client.get(
            reverse('content:find-article', args=[self.user_author.pk]) +
            '?filter=redaction')
        self.assertEqual(resp.status_code, 403)
        resp = self.client.get(
            reverse('content:find-article', args=[self.user_author.pk]) +
            '?filter=chuck-norris')
        self.assertEqual(resp.status_code, 404)

    def test_private_lists(self):
        tutorial = PublishedContentFactory(author_list=[self.user_author])
        tutorial_unpublished = PublishableContentFactory(
            author_list=[self.user_author])
        article = PublishedContentFactory(author_list=[self.user_author],
                                          type='ARTICLE')
        article_unpublished = PublishableContentFactory(
            author_list=[self.user_author], type='ARTICLE')
        self.client.login(username=self.user_author.username,
                          password='******')
        resp = self.client.get(
            reverse('content:find-tutorial', args=[self.user_author.pk]))
        self.assertContains(resp, tutorial.title)
        self.assertContains(resp, tutorial_unpublished.title)
        self.assertContains(resp, 'content-illu')
        resp = self.client.get(
            reverse('content:find-article', args=[self.user_author.pk]))
        self.assertContains(resp, article.title)
        self.assertContains(resp, article_unpublished.title)
        self.assertContains(resp, 'content-illu')

    def test_validation_list(self):
        """ensure the behavior of the `validation:list` page (with filters)"""

        text = u'Ceci est un éléphant'

        tuto_not_reserved = PublishableContentFactory(
            type='TUTORIAL', author_list=[self.user_author])
        tuto_reserved = PublishableContentFactory(
            type='TUTORIAL', author_list=[self.user_author])
        article_not_reserved = PublishableContentFactory(
            type='ARTICLE', author_list=[self.user_author])
        article_reserved = PublishableContentFactory(
            type='ARTICLE', author_list=[self.user_author])

        all_contents = [
            tuto_not_reserved, tuto_reserved, article_not_reserved,
            article_reserved
        ]
        reserved_contents = [tuto_reserved, article_reserved]

        # apply a filter to test category filter
        subcat = SubCategoryFactory()
        article_reserved.subcategory.add(subcat)
        article_reserved.save()

        # send in validation
        for content in all_contents:
            v = ValidationFactory(content=content, status='PENDING')
            v.date_proposition = datetime.datetime.now()
            v.version = content.sha_draft
            v.comment_authors = text

            if content in reserved_contents:
                v.validator = self.user_staff
                v.date_reserve = datetime.datetime.now()
                v.status = 'PENDING_V'

            v.save()

        # first, test access for public
        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code,
                         302)  # get 302 → redirection to login

        # connect with author:
        self.assertEqual(
            self.client.login(username=self.user_author.username,
                              password='******'), True)

        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 403)  # get 403 not allowed

        self.client.logout()

        # connect with staff:
        self.assertEqual(
            self.client.login(username=self.user_staff.username,
                              password='******'), True)

        response = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(response.status_code, 200)  # OK

        validations = response.context['validations']
        self.assertEqual(len(validations),
                         4)  # a total of 4 contents in validation

        # test filters
        response = self.client.get(reverse('validation:list') +
                                   '?type=article',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=tuto',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=orphan',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 not-reserved content

        for validation in validations:
            self.assertFalse(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') +
                                   '?type=reserved',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 reserved content

        for validation in validations:
            self.assertTrue(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') +
                                   '?subcategory={}'.format(subcat.pk),
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 1)  # 1 content with this category

        self.assertEqual(validations[0].content,
                         article_reserved)  # the right content

    def tearDown(self):

        if os.path.isdir(settings.ZDS_APP['content']['repo_private_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_private_path'])
        if os.path.isdir(settings.ZDS_APP['content']['repo_public_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_public_path'])
        if os.path.isdir(settings.MEDIA_ROOT):
            shutil.rmtree(settings.MEDIA_ROOT)

        # re-activate PDF build
        settings.ZDS_APP['content']['build_pdf_when_published'] = True
Beispiel #31
0
    def test_validation_list(self):
        """ensure the behavior of the `validation:list` page (with filters)"""

        text = u'Ceci est un éléphant'

        tuto_not_reserved = PublishableContentFactory(
            type='TUTORIAL', author_list=[self.user_author])
        tuto_reserved = PublishableContentFactory(
            type='TUTORIAL', author_list=[self.user_author])
        article_not_reserved = PublishableContentFactory(
            type='ARTICLE', author_list=[self.user_author])
        article_reserved = PublishableContentFactory(
            type='ARTICLE', author_list=[self.user_author])

        all_contents = [
            tuto_not_reserved, tuto_reserved, article_not_reserved,
            article_reserved
        ]
        reserved_contents = [tuto_reserved, article_reserved]

        # apply a filter to test category filter
        subcat = SubCategoryFactory()
        article_reserved.subcategory.add(subcat)
        article_reserved.save()

        # send in validation
        for content in all_contents:
            v = ValidationFactory(content=content, status='PENDING')
            v.date_proposition = datetime.datetime.now()
            v.version = content.sha_draft
            v.comment_authors = text

            if content in reserved_contents:
                v.validator = self.user_staff
                v.date_reserve = datetime.datetime.now()
                v.status = 'PENDING_V'

            v.save()

        # first, test access for public
        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code,
                         302)  # get 302 → redirection to login

        # connect with author:
        self.assertEqual(
            self.client.login(username=self.user_author.username,
                              password='******'), True)

        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 403)  # get 403 not allowed

        self.client.logout()

        # connect with staff:
        self.assertEqual(
            self.client.login(username=self.user_staff.username,
                              password='******'), True)

        response = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(response.status_code, 200)  # OK

        validations = response.context['validations']
        self.assertEqual(len(validations),
                         4)  # a total of 4 contents in validation

        # test filters
        response = self.client.get(reverse('validation:list') +
                                   '?type=article',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=tuto',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=orphan',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 not-reserved content

        for validation in validations:
            self.assertFalse(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') +
                                   '?type=reserved',
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 reserved content

        for validation in validations:
            self.assertTrue(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') +
                                   '?subcategory={}'.format(subcat.pk),
                                   follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 1)  # 1 content with this category

        self.assertEqual(validations[0].content,
                         article_reserved)  # the right content
Beispiel #32
0
    def test_unregister(self):
        """
        To test that unregistering user is working.
        """

        # test not logged user can't unregister.
        self.client.logout()
        result = self.client.post(reverse('member-unregister'), follow=False)
        self.assertEqual(result.status_code, 302)

        # test logged user can register.
        user = ProfileFactory()
        login_check = self.client.login(username=user.user.username,
                                        password='******')
        self.assertEqual(login_check, True)
        result = self.client.post(reverse('member-unregister'), follow=False)
        self.assertEqual(result.status_code, 302)
        self.assertEqual(
            User.objects.filter(username=user.user.username).count(), 0)

        # Attach a user at tutorials, articles, topics and private topics. After that,
        # unregister this user and check that he is well removed in all contents.
        user = ProfileFactory()
        user2 = ProfileFactory()
        alone_gallery = GalleryFactory()
        UserGalleryFactory(gallery=alone_gallery, user=user.user)
        shared_gallery = GalleryFactory()
        UserGalleryFactory(gallery=shared_gallery, user=user.user)
        UserGalleryFactory(gallery=shared_gallery, user=user2.user)
        # first case : a published tutorial with only one author
        published_tutorial_alone = PublishedContentFactory(type='TUTORIAL')
        published_tutorial_alone.authors.add(user.user)
        published_tutorial_alone.save()
        # second case : a published tutorial with two authors
        published_tutorial_2 = PublishedContentFactory(type='TUTORIAL')
        published_tutorial_2.authors.add(user.user)
        published_tutorial_2.authors.add(user2.user)
        published_tutorial_2.save()
        # third case : a private tutorial with only one author
        writing_tutorial_alone = PublishableContentFactory(type='TUTORIAL')
        writing_tutorial_alone.authors.add(user.user)
        writing_tutorial_alone.save()
        writing_tutorial_alone_galler_path = writing_tutorial_alone.gallery.get_gallery_path(
        )
        # fourth case : a private tutorial with at least two authors
        writing_tutorial_2 = PublishableContentFactory(type='TUTORIAL')
        writing_tutorial_2.authors.add(user.user)
        writing_tutorial_2.authors.add(user2.user)
        writing_tutorial_2.save()
        self.client.login(username=self.staff.username, password="******")
        # same thing for articles
        published_article_alone = PublishedContentFactory(type='ARTICLE')
        published_article_alone.authors.add(user.user)
        published_article_alone.save()
        published_article_2 = PublishedContentFactory(type='ARTICLE')
        published_article_2.authors.add(user.user)
        published_article_2.authors.add(user2.user)
        published_article_2.save()
        writing_article_alone = PublishableContentFactory(type='ARTICLE')
        writing_article_alone.authors.add(user.user)
        writing_article_alone.save()
        writing_article_2 = PublishableContentFactory(type='ARTICLE')
        writing_article_2.authors.add(user.user)
        writing_article_2.authors.add(user2.user)
        writing_article_2.save()
        # beta content
        beta_forum = ForumFactory(category=CategoryFactory())
        beta_content = BetaContentFactory(author_list=[user.user],
                                          forum=beta_forum)
        beta_content_2 = BetaContentFactory(
            author_list=[user.user, user2.user], forum=beta_forum)
        # about posts and topics
        authored_topic = TopicFactory(author=user.user, forum=self.forum11)
        answered_topic = TopicFactory(author=user2.user, forum=self.forum11)
        PostFactory(topic=answered_topic, author=user.user, position=2)
        edited_answer = PostFactory(topic=answered_topic,
                                    author=user.user,
                                    position=3)
        edited_answer.editor = user.user
        edited_answer.save()

        upvoted_answer = PostFactory(topic=answered_topic,
                                     author=user2.user,
                                     position=4)
        upvoted_answer.like += 1
        upvoted_answer.save()
        CommentVote.objects.create(user=user.user,
                                   comment=upvoted_answer,
                                   positive=True)

        private_topic = PrivateTopicFactory(author=user.user)
        private_topic.participants.add(user2.user)
        private_topic.save()
        PrivatePostFactory(author=user.user,
                           privatetopic=private_topic,
                           position_in_topic=1)

        # add API key
        self.assertEqual(Application.objects.count(), 0)
        self.assertEqual(AccessToken.objects.count(), 0)
        api_application = Application()
        api_application.client_id = 'foobar'
        api_application.user = user.user
        api_application.client_type = 'confidential'
        api_application.authorization_grant_type = 'password'
        api_application.client_secret = '42'
        api_application.save()
        token = AccessToken()
        token.user = user.user
        token.token = 'r@d0m'
        token.application = api_application
        token.expires = datetime.now()
        token.save()
        self.assertEqual(Application.objects.count(), 1)
        self.assertEqual(AccessToken.objects.count(), 1)

        # login and unregister:
        login_check = self.client.login(username=user.user.username,
                                        password='******')
        self.assertEqual(login_check, True)
        result = self.client.post(reverse('member-unregister'), follow=False)
        self.assertEqual(result.status_code, 302)

        # check that the bot have taken authorship of tutorial:
        self.assertEqual(published_tutorial_alone.authors.count(), 1)
        self.assertEqual(published_tutorial_alone.authors.first().username,
                         settings.ZDS_APP["member"]["external_account"])
        self.assertFalse(os.path.exists(writing_tutorial_alone_galler_path))
        self.assertEqual(published_tutorial_2.authors.count(), 1)
        self.assertEqual(
            published_tutorial_2.authors.filter(
                username=settings.ZDS_APP["member"]
                ["external_account"]).count(), 0)

        # check that published tutorials remain published and accessible
        self.assertIsNotNone(
            published_tutorial_2.public_version.get_prod_path())
        self.assertTrue(
            os.path.exists(
                published_tutorial_2.public_version.get_prod_path()))
        self.assertIsNotNone(
            published_tutorial_alone.public_version.get_prod_path())
        self.assertTrue(
            os.path.exists(
                published_tutorial_alone.public_version.get_prod_path()))
        self.assertEqual(
            self.client.get(reverse('tutorial:view',
                                    args=[
                                        published_tutorial_alone.pk,
                                        published_tutorial_alone.slug
                                    ]),
                            follow=False).status_code, 200)
        self.assertEqual(
            self.client.get(reverse(
                'tutorial:view',
                args=[published_tutorial_2.pk, published_tutorial_2.slug]),
                            follow=False).status_code, 200)

        # test that published articles remain accessible
        self.assertTrue(
            os.path.exists(
                published_article_alone.public_version.get_prod_path()))
        self.assertEqual(
            self.client.get(reverse('article:view',
                                    args=[
                                        published_article_alone.pk,
                                        published_article_alone.slug
                                    ]),
                            follow=True).status_code, 200)
        self.assertEqual(
            self.client.get(reverse(
                'article:view',
                args=[published_article_2.pk, published_article_2.slug]),
                            follow=True).status_code, 200)

        # check that the tutorial for which the author was alone does not exists anymore
        self.assertEqual(
            PublishableContent.objects.filter(
                pk=writing_tutorial_alone.pk).count(), 0)
        self.assertFalse(os.path.exists(
            writing_tutorial_alone.get_repo_path()))

        # check that bot haven't take the authorship of the tuto with more than one author
        self.assertEqual(writing_tutorial_2.authors.count(), 1)
        self.assertEqual(
            writing_tutorial_2.authors.filter(
                username=settings.ZDS_APP["member"]
                ["external_account"]).count(), 0)

        # authorship for the article for which user was the only author
        self.assertEqual(published_article_alone.authors.count(), 1)
        self.assertEqual(published_article_alone.authors.first().username,
                         settings.ZDS_APP["member"]["external_account"])
        self.assertEqual(published_article_2.authors.count(), 1)

        self.assertEqual(
            PublishableContent.objects.filter(
                pk=writing_article_alone.pk).count(), 0)
        self.assertFalse(os.path.exists(writing_article_alone.get_repo_path()))

        # not bot if another author:
        self.assertEqual(
            published_article_2.authors.filter(
                username=settings.ZDS_APP["member"]
                ["external_account"]).count(), 0)
        self.assertEqual(writing_article_2.authors.count(), 1)
        self.assertEqual(
            writing_article_2.authors.filter(
                username=settings.ZDS_APP["member"]
                ["external_account"]).count(), 0)

        # topics, gallery and PMs:
        self.assertEqual(
            Topic.objects.filter(author__username=user.user.username).count(),
            0)
        self.assertEqual(
            Post.objects.filter(author__username=user.user.username).count(),
            0)
        self.assertEqual(
            Post.objects.filter(editor__username=user.user.username).count(),
            0)
        self.assertEqual(
            PrivatePost.objects.filter(
                author__username=user.user.username).count(), 0)
        self.assertEqual(
            PrivateTopic.objects.filter(
                author__username=user.user.username).count(), 0)

        self.assertIsNotNone(Topic.objects.get(pk=authored_topic.pk))
        self.assertIsNotNone(PrivateTopic.objects.get(pk=private_topic.pk))
        self.assertIsNotNone(Gallery.objects.get(pk=alone_gallery.pk))
        self.assertEquals(alone_gallery.get_linked_users().count(), 1)
        self.assertEquals(shared_gallery.get_linked_users().count(), 1)
        self.assertEquals(
            UserGallery.objects.filter(user=user.user).count(), 0)
        self.assertEquals(
            CommentVote.objects.filter(user=user.user, positive=True).count(),
            0)
        self.assertEquals(
            Post.objects.filter(pk=upvoted_answer.id).first().like, 0)

        # zep 12, published contents and beta
        self.assertIsNotNone(
            PublishedContent.objects.filter(
                content__pk=published_tutorial_alone.pk).first())
        self.assertIsNotNone(
            PublishedContent.objects.filter(
                content__pk=published_tutorial_2.pk).first())
        self.assertTrue(
            Topic.objects.get(pk=beta_content.beta_topic.pk).is_locked)
        self.assertFalse(
            Topic.objects.get(pk=beta_content_2.beta_topic.pk).is_locked)

        # check API
        self.assertEqual(Application.objects.count(), 0)
        self.assertEqual(AccessToken.objects.count(), 0)
Beispiel #33
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
Beispiel #34
0
class UtilsTests(TestCase):

    def setUp(self):

        # don't build PDF to speed up the tests
        settings.ZDS_APP['content']['build_pdf_when_published'] = False

        settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
        self.mas = ProfileFactory().user
        settings.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 PublicatorRegistery.get_all_registered()}

    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(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)  # its 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')))
        self.assertTrue(os.path.isfile(public.get_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.

        # 2. Mini-tutorial → Not tested, because at this point, it's the same as an article (with a different metadata)
        # 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_objet=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_objet=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)  # its 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 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)

        # 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_objet=bigtuto)
        chapter1 = ContainerFactory(parent=part1, db_objet=bigtuto)
        ExtractFactory(container=chapter1, db_object=bigtuto)
        part2 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto)
        chapter2 = ContainerFactory(parent=part2, db_objet=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)  # its 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_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 = {}
        shutil.copy(
            os.path.join(BASE_DIR, "fixtures", "tuto", "balise_audio", "manifest.json"),
            os.path.join(BASE_DIR, "fixtures", "tuto", "balise_audio", "manifest2.json")
        )
        LicenceFactory(code="CC BY")
        args = [os.path.join(BASE_DIR, "fixtures", "tuto", "balise_audio", "manifest2.json")]
        call_command('upgrade_manifest_to_v2', *args, **opts)
        manifest = open(os.path.join(BASE_DIR, "fixtures", "tuto", "balise_audio", "manifest2.json"), 'r')
        json = json_reader.loads(manifest.read())

        self.assertTrue(u"version" in json)
        self.assertTrue(u"licence" in json)
        self.assertTrue(u"children" in json)
        self.assertEqual(len(json[u"children"]), 3)
        self.assertEqual(json[u"children"][0][u"object"], u"extract")
        os.unlink(args[0])
        args = [os.path.join(BASE_DIR, "fixtures", "tuto", "big_tuto_v1", "manifest2.json")]
        shutil.copy(
            os.path.join(BASE_DIR, "fixtures", "tuto", "big_tuto_v1", "manifest.json"),
            os.path.join(BASE_DIR, "fixtures", "tuto", "big_tuto_v1", "manifest2.json")
        )
        call_command('upgrade_manifest_to_v2', *args, **opts)
        manifest = open(os.path.join(BASE_DIR, "fixtures", "tuto", "big_tuto_v1", "manifest2.json"), 'r')
        json = json_reader.loads(manifest.read())
        os.unlink(args[0])
        self.assertTrue(u"version" in json)
        self.assertTrue(u"licence" in json)
        self.assertTrue(u"children" in json)
        self.assertEqual(len(json[u"children"]), 5)
        self.assertEqual(json[u"children"][0][u"object"], u"container")
        self.assertEqual(len(json[u"children"][0][u"children"]), 3)
        self.assertEqual(len(json[u"children"][0][u"children"][0][u"children"]), 3)
        args = [os.path.join(BASE_DIR, "fixtures", "tuto", "article_v1", "manifest2.json")]
        shutil.copy(
            os.path.join(BASE_DIR, "fixtures", "tuto", "article_v1", "manifest.json"),
            os.path.join(BASE_DIR, "fixtures", "tuto", "article_v1", "manifest2.json")
        )
        call_command('upgrade_manifest_to_v2', *args, **opts)
        manifest = open(os.path.join(BASE_DIR, "fixtures", "tuto", "article_v1", "manifest2.json"), 'r')
        json = json_reader.loads(manifest.read())

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

    def test_retrieve_images(self):
        """test the ``retrieve_and_update_images_links()`` function.

        NOTE: this test require an working internet connection to succeed
        Also, it was implemented with small images on highly responsive server(s), to make it quick !
        """

        tempdir = os.path.join(tempfile.gettempdir(), 'test_retrieve_imgs')
        os.makedirs(tempdir)

        # image which exists, or not
        test_images = [
            # PNG:
            ('http://upload.wikimedia.org/wikipedia/en/9/9d/Commons-logo-31px.png', 'Commons-logo-31px.png'),
            # JPEG:
            ('http://upload.wikimedia.org/wikipedia/commons/6/6b/01Aso.jpg', '01Aso.jpg'),
            # Image which does not exists:
            ('http://test.com/test idiot.png', 'test_idiot.png'),  # NOTE: space changed into `_` !
            # SVG (will be converted to png):
            ('http://upload.wikimedia.org/wikipedia/commons/f/f9/10DF.svg', '10DF.png'),
            # GIF (will be converted to png):
            ('http://upload.wikimedia.org/wikipedia/commons/2/27/AnimatedStar.gif', 'AnimatedStar.png'),
            # local image:
            ('fixtures/image_test.jpg', 'image_test.jpg')
        ]

        # for each of these images, test that the url (and only that) is changed
        for url, filename in test_images:
            random_thing = str(datetime.datetime.now())  # will be used as legend, to ensure that this part remains
            an_image_link = '![{}]({})'.format(random_thing, url)
            new_image_url = 'images/{}'.format(filename)
            new_image_link = '![{}]({})'.format(random_thing, new_image_url)

            new_md = retrieve_and_update_images_links(an_image_link, tempdir)
            self.assertTrue(os.path.isfile(os.path.join(tempdir, new_image_url)))  # image was retrieved
            self.assertEqual(new_image_link, new_md)  # link was updated

        # then, ensure that 3 times the same images link make the code use three times the same image !
        link = '![{}](http://upload.wikimedia.org/wikipedia/commons/5/56/Asteroid_icon.jpg)'
        new_link = '![{}](images/Asteroid_icon.jpg)'
        three_times = ' '.join([link.format(i) for i in range(0, 2)])
        three_times_updated = ' '.join([new_link.format(i) for i in range(0, 2)])

        new_md = retrieve_and_update_images_links(three_times, tempdir)
        self.assertEqual(three_times_updated, new_md)

        # ensure that the original file is deleted if any
        another_svg = '![](http://upload.wikimedia.org/wikipedia/commons/3/32/Arrow.svg)'
        new_md = retrieve_and_update_images_links(another_svg, tempdir)
        self.assertEqual('![](images/Arrow.png)', new_md)

        self.assertTrue(os.path.isfile(os.path.join(tempdir, 'images/Arrow.png')))  # image was converted in PNG
        self.assertFalse(os.path.isfile(os.path.join(tempdir, 'images/Arrow.svg')))  # and the original SVG was deleted

        # finally, clean up:
        shutil.rmtree(tempdir)

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

        settings.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.have_pdf())
        self.assertTrue(published2.have_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', 'id={}'.format(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")
        newUser = ProfileFactory().user
        reac = ContentReaction(author=self.user_author, position=1, related_content=article)
        reac.update_content("I will find you. And I Will Kill you.")
        reac.save()
        article.last_note = reac
        article.save()

        self.assertFalse(last_participation_is_old(article, newUser))
        ContentRead(user=self.user_author, note=reac, content=article).save()
        reac = ContentReaction(author=newUser, position=2, related_content=article)
        reac.update_content("I will find you. And I Will Kill you.")
        reac.save()
        article.last_note = reac
        article.save()
        ContentRead(user=newUser, note=reac, content=article).save()
        self.assertFalse(last_participation_is_old(article, newUser))
        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(u"un peu plus près de 42"))
        versioned.dump_json()
        manifest = os.path.join(versioned.get_path(), "manifest.json")
        dictionary = json_reader.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.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        # go to whatever page, if not, `get_current_user()` does not work at all
        result = self.client.get(reverse('zds.pages.views.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)

        # 2. Without connected user
        self.client.logout()

        # as above ...
        result = self.client.get(reverse('zds.pages.views.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 = [u'-', u'_', u'__', u'-_-', u'$', u'@', u'&', u'{}', u'    ', u'...']

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

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

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

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

    def test_watchdog(self):

        PublicatorRegistery.unregister("pdf")
        PublicatorRegistery.unregister("epub")
        PublicatorRegistery.unregister("html")

        with open("path", "w") as f:
            f.write("my_content;/path/to/markdown.md")

        @PublicatorRegistery.register("test", "", "")
        class TestPublicator(Publicator):
            def __init__(self, *__):
                pass

        PublicatorRegistery.get("test").publish = Mock()
        event = FileCreatedEvent("path")
        handler = TutorialIsPublished()
        handler.prepare_generation = Mock()
        handler.finish_generation = Mock()
        handler.on_created(event)

        self.assertTrue(PublicatorRegistery.get("test").publish.called)
        handler.finish_generation.assert_called_with("/path/to", "path")
        handler.prepare_generation.assert_called_with("/path/to")

    def tearDown(self):
        if os.path.isdir(settings.ZDS_APP['content']['repo_private_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_private_path'])
        if os.path.isdir(settings.ZDS_APP['content']['repo_public_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_public_path'])
        if os.path.isdir(settings.MEDIA_ROOT):
            shutil.rmtree(settings.MEDIA_ROOT)
        if os.path.isdir(settings.ZDS_APP['content']['extra_content_watchdog_dir']):
            shutil.rmtree(settings.ZDS_APP['content']['extra_content_watchdog_dir'])
        # re-active PDF build
        settings.ZDS_APP['content']['build_pdf_when_published'] = True
        PublicatorRegistery.registry = self.old_registry
Beispiel #35
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
Beispiel #36
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.assertTrue(self.client.login(username=self.user1.username, password='******'))

    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.new_content.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') + '?pk={}'.format(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.assertTrue(self.client.login(username=self.user2.username, password='******'), True)

        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.new_content.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.new_content.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())
Beispiel #37
0
    def test_special_case_of_contents(self):
        """test that the old publishedcontent does not stay when a new one is created"""

        if not self.manager.connected_to_es:
            return

        # 1. Create a middle-tutorial, publish it, then index it
        tuto = PublishableContentFactory(type='TUTORIAL')
        tuto.authors.add(self.user)
        tuto.save()

        tuto_draft = tuto.load_version()
        chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        ExtractFactory(container=chapter1, db_object=tuto)
        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, force_reindexing=True)  # index
        self.manager.refresh_index()

        first_publication = PublishedContent.objects.get(content_pk=tuto.pk)
        self.assertTrue(first_publication.es_already_indexed)
        self.assertFalse(first_publication.es_flagged)

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 2)  # get 2 results, one for the content and one for the chapter

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

        # 2. Change thet title, which will trigger a change in the slug
        tuto = PublishableContent.objects.get(pk=tuto.pk)
        versioned = tuto.load_version(sha=tuto.sha_draft)

        tuto.title = 'un titre complètement différent!'
        tuto.save()

        versioned.repo_update_top_container(tuto.title, tuto.slug, 'osef', 'osef')
        second_publication = publish_content(tuto, versioned, True)

        tuto.sha_public = versioned.current_version
        tuto.sha_draft = versioned.current_version
        tuto.public_version = second_publication
        tuto.save()

        self.assertEqual(PublishedContent.objects.count(), 2)  # now there is two objects ...
        first_publication = PublishedContent.objects.get(pk=first_publication.pk)
        self.assertTrue(first_publication.must_redirect)  # .. including the first one, for redirection

        self.manager.refresh_index()

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 0)  # the old one is gone (and we need to reindex to get the new one)

        # 3. Check if indexation brings the new one, and not the old one
        self.manager.es_bulk_indexing_of_model(PublishedContent, force_reindexing=True)  # index
        self.manager.refresh_index()

        first_publication = PublishedContent.objects.get(pk=first_publication.pk)
        second_publication = PublishedContent.objects.get(pk=second_publication.pk)

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 2)  # Still 2, not 4 !

        found_old = False
        found_new = False

        for hit in results:
            if hit.meta.doc_type == PublishedContent.get_es_document_type():
                if hit.meta.id == first_publication.es_id:
                    found_old = True
                if hit.meta.id == second_publication.es_id:
                    found_new = True

        self.assertTrue(found_new)
        self.assertFalse(found_old)
Beispiel #38
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()
     publish_content(tuto_1, tuto_1_draft, is_major_update=True)
Beispiel #39
0
def load_contents(cli, _type, size, fake):
    """Create v2 contents"""

    nb_contents = size * 10
    percent_contents_in_validation = 0.4
    percent_contents_with_validator = 0.2
    percent_contents_public = 0.3
    percent_mini = 0.5
    percent_medium = 0.3
    percent_big = 0.2
    nb_avg_containers_in_content = size
    nb_avg_extracts_in_content = size

    is_articles = _type == "ARTICLE"
    is_tutorials = not is_articles

    textual_type = u"article"
    if is_tutorials:
        textual_type = u"tutoriel"

    # small introduction
    cli.stdout.write(u'À créer: {:d} {}s'.format(nb_contents, textual_type), ending='')

    if is_tutorials:
        cli.stdout.write(u' ({:g} petits, {:g} moyens et {:g} grands)'
                         .format(nb_contents * percent_mini, nb_contents * percent_medium, nb_contents * percent_big))
    else:
        cli.stdout.write('')

    cli.stdout.write(
        u' - {:g} en brouillon'.format(
            nb_contents *
            (1 - percent_contents_public - percent_contents_in_validation - percent_contents_with_validator)))
    cli.stdout.write(
        u' - {:g} en validation (dont {:g} réservés)'
        .format(nb_contents * (percent_contents_in_validation + percent_contents_with_validator),
                nb_contents * percent_contents_with_validator))
    cli.stdout.write(u' - {:g} publiés'.format(nb_contents * percent_contents_public))

    tps1 = time.time()

    # create tables with 0=draft, 1=in validation, 2=reserved, 3=published
    what_to_do = []
    for i in range(nb_contents):
        what = 0  # in draft
        if i < percent_contents_public * nb_contents:
            what = 3
        elif i < (percent_contents_public + percent_contents_with_validator) * nb_contents:
            what = 2
        elif i >= (1 - percent_contents_in_validation) * nb_contents:
            what = 1
        what_to_do.append(what)

    # create a table with 0=mini, 1=medium, 2=big
    content_sizes = []
    for i in range(nb_contents):
        sz = 0
        if i < percent_big * nb_contents:
            sz = 2
        elif i >= (1 - percent_medium) * nb_contents:
            sz = 1
        content_sizes.append(sz)

    # shuffle the whole thing
    random.shuffle(what_to_do)
    random.shuffle(content_sizes)

    # checks that everything is ok
    users = list(Profile.objects.all())
    nb_users = len(users)
    sub_categories = list(SubCategory.objects.all())
    nb_sub_categories = len(sub_categories)
    if nb_users == 0:
        cli.stdout.write(u"Il n'y a aucun membre actuellement. "
                         u"Vous devez rajouter les membre dans vos fixtures (member)")
        return

    if nb_sub_categories == 0:
        cli.stdout.write(u"Il n'y a aucune catégories actuellement."
                         u"Vous devez rajouter les catégories dans vos fixtures (category_content)")
        return

    perms = list(Permission.objects.filter(codename__startswith='change_').all())
    staffs = list(User.objects.filter(groups__permissions__in=perms).all())
    nb_staffs = len(staffs)

    if nb_staffs == 0:
        cli.stdout.write(u"Il n'y a aucun staff actuellement."
                         u"Vous devez rajouter les staffs dans vos fixtures (staff)")
        return

    licenses = list(Licence.objects.all())
    nb_licenses = len(licenses)

    if nb_licenses == 0:
        cli.stdout.write(u"Il n'y a aucune licence actuellement."
                         u"Vous devez rajouter les licences dans vos fixtures (category_content)")
        return

    # create and so all:
    for i in range(nb_contents):
        sys.stdout.write("Création {} : {}/{}  \r".format(textual_type, i + 1, nb_contents))

        current_size = content_sizes[i]
        to_do = what_to_do[i]

        # creation:
        content = PublishableContentFactory(
            type=_type,
            title=fake.text(max_nb_chars=60),
            description=fake.sentence(nb_words=15, variable_nb_words=True))

        versioned = content.load_version()

        if current_size == 0 or is_articles:
            for j in range(random.randint(1, nb_avg_extracts_in_content * 2)):
                ExtractFactory(container=versioned, title=fake.text(max_nb_chars=60), light=False)
        else:
            for j in range(random.randint(1, nb_avg_containers_in_content * 2)):
                container = ContainerFactory(parent=versioned, title=fake.text(max_nb_chars=60))

                if current_size == 1:  # medium size tutorial
                    for k in range(random.randint(1, nb_avg_extracts_in_content * 2)):
                        ExtractFactory(container=container, title=fake.text(max_nb_chars=60), light=False)
                else:  # big-size tutorial
                    for k in range(random.randint(1, nb_avg_containers_in_content * 2)):
                        subcontainer = ContainerFactory(parent=container, title=fake.text(max_nb_chars=60))

                        for l in range(random.randint(1, nb_avg_extracts_in_content * 2)):
                            ExtractFactory(container=subcontainer, title=fake.text(max_nb_chars=60), light=False)

        # add some informations:
        author = users[random.randint(0, nb_users - 1)].user
        content.authors.add(author)
        UserGalleryFactory(gallery=content.gallery, mode="W", user=author)
        content.licence = licenses[random.randint(0, nb_licenses - 1)]
        content.sha_draft = versioned.sha_draft
        content.subcategory.add(sub_categories[random.randint(0, nb_sub_categories - 1)])
        content.save()

        # then, validation if needed:
        if to_do > 0:
            valid = CValidation(
                content=content, version=content.sha_draft, date_proposition=datetime.now(), status="PENDING")
            valid.comment_validator = fake.text(max_nb_chars=200)

            content.sha_validation = content.sha_draft

            if to_do > 1:  # reserve validation
                valid.date_reserve = datetime.now()
                valid.validator = staffs[random.randint(0, nb_staffs - 1)]
                valid.status = "PENDING_V"
            if to_do > 2:  # publish content
                valid.comment_validator = fake.text(max_nb_chars=80)
                valid.status = "ACCEPT"
                valid.date_validation = datetime.now()
                content.sha_public = content.sha_draft

                published = publish_content(content, versioned)
                content.public_version = published

            valid.save()
            content.save()

        sys.stdout.flush()

    tps2 = time.time()
    cli.stdout.write(u"\nFait en {:.3f} sec".format(tps2 - tps1))
Beispiel #40
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
Beispiel #41
0
class TryToIndexTutorialTests(TestCase):
    def setUp(self):

        # don't build PDF to speed up the tests
        settings.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
        settings.ZDS_APP['member']['bot_account'] = self.mas.username

        bot = Group(name=settings.ZDS_APP["member"]["bot_group"])
        bot.save()
        self.external = UserFactory(
            username=settings.ZDS_APP["member"]["external_account"],
            password="******")

        self.beta_forum = ForumFactory(
            pk=settings.ZDS_APP['forum']['beta_forum_id'],
            category=CategoryFactory(position=1),
            position_in_category=1
        )  # ensure that the forum, for the beta versions, is created

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

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().user

        # create a tutorial
        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.subcategory.add(self.subcategory)
        self.tuto.save()

        # fill it with one part, containing one chapter, containing one extract
        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.extract1 = ExtractFactory(container=self.chapter1,
                                       db_object=self.tuto)

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

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

        # create an article
        self.article = PublishableContentFactory(type='ARTICLE')
        self.article.authors.add(self.user_author)
        UserGalleryFactory(gallery=self.article.gallery,
                           user=self.user_author,
                           mode='W')
        self.article.licence = self.licence
        self.article.subcategory.add(self.subcategory)
        self.article.save()

        # fill it with one extract
        self.article_draft = self.article.load_version()
        self.extract1 = ExtractFactory(container=self.article_draft,
                                       db_object=self.article)

        # then, publish it !
        version = self.article_draft.current_version
        self.published_article = publish_content(self.article,
                                                 self.article_draft,
                                                 is_major_update=True)

        self.article.sha_public = version
        self.article.sha_draft = version
        self.article.public_version = self.published_article
        self.article.save()

    def test_index_tutorial_article(self):
        """
        Can at publication time, index a tutorial, this is what we aim for this test.

        We wanted to test, if we can save a tutorial in the search tables. This test cover reindex_thread method in
        search/utils.py file.

        This test doesn't do a verification in the search engine, it just test, if we can save the tutorial in the
        database.
        """

        # Reindex the tutorial
        reindex_content(self.published_tuto)
        reindex_content(self.published_article)

        self.assertEqual(SearchIndexContent.objects.count(), 2)
        self.assertEqual(SearchIndexContainer.objects.count(), 2)
        self.assertEqual(SearchIndexExtract.objects.count(), 2)

        for content in SearchIndexContent.objects.all():
            if content.type == 'article':
                self.assertIsNotNone(content.publishable_content)
                self.assertEqual(content.title, self.article.title)
                self.assertEqual(content.description, self.article.description)

                self.assertEqual(content.licence, self.licence.title)
                if self.article.image:
                    self.assertEqual(content.url_image,
                                     self.article.image.get_absolute_url())

                self.assertEqual(content.tags.count(), 1)
                self.assertEqual(content.authors.count(), 1)
            else:
                self.assertIsNotNone(content.publishable_content)
                self.assertEqual(content.title, self.tuto.title)
                self.assertEqual(content.description, self.tuto.description)

                self.assertEqual(content.licence, self.licence.title)
                if self.tuto.image:
                    self.assertEqual(content.url_image,
                                     self.tuto.image.get_absolute_url())

                self.assertEqual(content.tags.count(), 1)
                self.assertEqual(content.authors.count(), 1)

    def test_filter_keyword(self):
        html = "<h1>Keyword h1</h1><h2>Keyword h2</h2><strong>Keyword strong</strong><em>Keyword italic</em>"

        keywords = filter_keyword(html)

        self.assertIn('Keyword h1', keywords)
        self.assertIn('Keyword h2', keywords)
        self.assertIn('Keyword strong', keywords)
        self.assertIn('Keyword italic', keywords)

    def test_filter_text(self):
        html = "<h1>Keyword h1</h1><h2>Keyword h2</h2><strong>Keyword strong</strong><em>Keyword italic</em>"

        words = filter_text(html)

        self.assertIn('Keyword h1', words)
        self.assertIn('Keyword h2', words)
        self.assertIn('Keyword strong', words)
        self.assertIn('Keyword italic', words)

    def tearDown(self):

        if os.path.isdir(settings.ZDS_APP['content']['repo_private_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_private_path'])
        if os.path.isdir(settings.ZDS_APP['content']['repo_public_path']):
            shutil.rmtree(settings.ZDS_APP['content']['repo_public_path'])
        if os.path.isdir(settings.MEDIA_ROOT):
            shutil.rmtree(settings.MEDIA_ROOT)
Beispiel #42
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 !
Beispiel #43
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.is_solved = True
        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
Beispiel #44
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)
Beispiel #45
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)
Beispiel #46
0
    def test_publish_content(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)  # its 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')))
        self.assertTrue(os.path.isfile(public.get_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.

        # 2. Mini-tutorial → Not tested, because at this point, it's the same as an article (with a different metadata)
        # 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_objet=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_objet=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)  # its 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 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)

        # 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_objet=bigtuto)
        chapter1 = ContainerFactory(parent=part1, db_objet=bigtuto)
        ExtractFactory(container=chapter1, db_object=bigtuto)
        part2 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto)
        chapter2 = ContainerFactory(parent=part2, db_objet=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)  # its 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_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.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        # 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.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)
        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']))
Beispiel #48
0
    def test_indexation(self):
        """test the indexation and deletion of the different documents"""

        if not self.manager.connected_to_es:
            return

        # create a topic with a post
        topic = TopicFactory(forum=self.forum, author=self.user)
        post = PostFactory(topic=topic, author=self.user, position=1)

        topic = Topic.objects.get(pk=topic.pk)
        post = Post.objects.get(pk=post.pk)

        self.assertFalse(topic.es_already_indexed)
        self.assertTrue(topic.es_flagged)
        self.assertFalse(post.es_already_indexed)
        self.assertTrue(post.es_flagged)

        # create a middle-tutorial and publish it
        tuto = PublishableContentFactory(type='TUTORIAL')
        tuto.authors.add(self.user)
        tuto.save()

        tuto_draft = tuto.load_version()
        chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto)
        ExtractFactory(container=chapter1, db_object=tuto)
        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.get(content_pk=tuto.pk)
        self.assertFalse(published.es_already_indexed)
        self.assertTrue(published.es_flagged)

        # 1. index all
        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model, force_reindexing=False)
            self.manager.refresh_index()

        topic = Topic.objects.get(pk=topic.pk)
        post = Post.objects.get(pk=post.pk)

        self.assertTrue(topic.es_already_indexed)
        self.assertFalse(topic.es_flagged)
        self.assertTrue(post.es_already_indexed)
        self.assertFalse(post.es_flagged)

        published = PublishedContent.objects.get(content_pk=tuto.pk)
        self.assertTrue(published.es_already_indexed)
        self.assertFalse(published.es_flagged)

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 4)  # get 4 results, one of each type

        must_contain = {'post': False, 'topic': False, 'publishedcontent': False, 'chapter': False}
        id_must_be = {
            'post': str(post.pk),
            'topic': str(topic.pk),
            'publishedcontent': str(published.pk),
            'chapter': tuto.slug + '__' + chapter1.slug
        }

        for hit in results:
            doc_type = hit.meta.doc_type
            must_contain[doc_type] = True
            self.assertEqual(hit.meta.id, id_must_be[doc_type])

        self.assertTrue(all(must_contain))

        # 2. Test what reindexation will do:
        new_topic = TopicFactory(forum=self.forum, author=self.user)
        new_post = PostFactory(topic=new_topic, author=self.user, position=1)

        pk_of_topics_to_reindex = []
        for item in Topic.get_es_indexable(force_reindexing=False):
            pk_of_topics_to_reindex.append(item.pk)

        pk_of_posts_to_reindex = []
        for item in Post.get_es_indexable(force_reindexing=False):
            pk_of_posts_to_reindex.append(item.pk)

        self.assertTrue(topic.pk not in pk_of_topics_to_reindex)
        self.assertTrue(new_topic.pk in pk_of_topics_to_reindex)
        self.assertTrue(post.pk not in pk_of_posts_to_reindex)
        self.assertTrue(new_post.pk in pk_of_posts_to_reindex)

        for model in self.indexable:  # ok, so let's index that
            if model is FakeChapter:
                continue
            self.manager.es_bulk_indexing_of_model(model, force_reindexing=False)
        self.manager.refresh_index()

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 6)  # good!

        # 3. Test single deletion:
        new_post = Post.objects.get(pk=new_post.pk)

        self.manager.delete_document(new_post)
        self.manager.refresh_index()

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 5)  # one is missing

        for hit in results:
            self.assertTrue(hit.meta.doc_type != Post.get_es_document_type() or hit.meta.id != new_post.es_id)

        # 4. Test "delete_by_query_deletion":
        topic = Topic.objects.get(pk=topic.pk)
        new_topic = Topic.objects.get(pk=new_topic.pk)

        self.manager.delete_by_query(Topic.get_es_document_type(), MatchAll())  # the two topic are deleted
        self.manager.refresh_index()

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 3)

        for hit in results:
            self.assertTrue(hit.meta.doc_type != Topic.get_es_document_type() or hit.meta.id != new_topic.es_id)
            self.assertTrue(hit.meta.doc_type != Topic.get_es_document_type() or hit.meta.id != topic.es_id)

        # 5. Test that the deletion of an object also triggers its deletion in ES
        post = Post.objects.get(pk=post.pk)
        post.delete()
        self.manager.refresh_index()

        s = Search()
        s.query(MatchAll())
        results = self.manager.setup_search(s).execute()
        self.assertEqual(len(results), 2)

        for hit in results:
            self.assertTrue(hit.meta.doc_type != Post.get_es_document_type() or hit.meta.id != post.es_id)

        # 6. Test full desindexation:
        for model in self.indexable:
            if model is FakeChapter:
                continue
            self.manager.clear_indexing_of_model(model)

        # note "topic" is gone since "post" is gone, due to relationships at the Django level
        new_topic = Topic.objects.get(pk=new_topic.pk)
        new_post = Post.objects.get(pk=new_post.pk)

        self.assertFalse(new_topic.es_already_indexed)
        self.assertTrue(new_topic.es_flagged)
        self.assertFalse(new_post.es_already_indexed)
        self.assertTrue(new_post.es_flagged)

        published = PublishedContent.objects.get(content_pk=tuto.pk)
        self.assertFalse(published.es_already_indexed)
        self.assertTrue(published.es_flagged)
    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.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        # 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.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)

        # 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)
Beispiel #50
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)
    def test_opinion_conversion(self):
        """
        Test the conversion of PublishableContent with type=OPINION
        to PublishableContent with type=ARTICLE
        """

        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.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        # 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
        result = self.client.post(
            reverse('validation:promote-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}),
            {
                'source': '',
                'version': opinion_draft.current_version
            },
            follow=False)
        self.assertEqual(result.status_code, 403)

        self.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)

        # valid with staff
        result = self.client.post(
            reverse('validation:promote-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}),
            {
                'source': '',
                'version': opinion_draft.current_version
            },
            follow=False)
        self.assertEqual(result.status_code, 302)
Beispiel #52
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 !
    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.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        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.assertEqual(
            self.client.login(
                username=random_user.username,
                password='******'),
            True)

        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.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)

        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)
Beispiel #54
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)
Beispiel #55
0
    def test_validation_list(self):
        """ensure the behavior of the `validation:list` page (with filters)"""

        text = 'Ceci est un éléphant'

        tuto_not_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author])
        tuto_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author])
        article_not_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author])
        article_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author])

        all_contents = [tuto_not_reserved, tuto_reserved, article_not_reserved, article_reserved]
        reserved_contents = [tuto_reserved, article_reserved]

        # apply a filter to test category filter
        subcat = SubCategoryFactory()
        article_reserved.subcategory.add(subcat)
        article_reserved.save()

        # send in validation
        for content in all_contents:
            v = ValidationFactory(content=content, status='PENDING')
            v.date_proposition = datetime.datetime.now()
            v.version = content.sha_draft
            v.comment_authors = text

            if content in reserved_contents:
                v.validator = self.user_staff
                v.date_reserve = datetime.datetime.now()
                v.status = 'PENDING_V'

            v.save()

        # first, test access for public
        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 302)  # get 302 → redirection to login

        # connect with author:
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 403)  # get 403 not allowed

        self.client.logout()

        # connect with staff:
        self.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)

        response = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(response.status_code, 200)  # OK

        validations = response.context['validations']
        self.assertEqual(len(validations), 4)  # a total of 4 contents in validation

        # test filters
        response = self.client.get(reverse('validation:list') + '?type=article', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=tuto', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=orphan', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 not-reserved content

        for validation in validations:
            self.assertFalse(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') + '?type=reserved', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 reserved content

        for validation in validations:
            self.assertTrue(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') + '?subcategory={}'.format(subcat.pk), follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 1)  # 1 content with this category

        self.assertEqual(validations[0].content, article_reserved)  # the right content
Beispiel #56
0
class ContentNotification(TestCase, TutorialTestMixin):
    def setUp(self):

        # don't build PDF to speed up the tests
        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.assertTrue(self.client.login(username=self.user1.username, password='******'))

    def test_no_persistant_notif_on_revoke(self):
        from zds.tutorialv2.publication_utils import unpublish_content
        NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2)
        content = PublishedContentFactory(author_list=[self.user2])

        notif_signals.new_content.send(sender=self.tuto.__class__, instance=content, by_email=False)
        self.assertEqual(1, len(Notification.objects.get_notifications_of(self.user1)))
        unpublish_content(content)
        self.assertEqual(0, len(Notification.objects.get_notifications_of(self.user1)))

    def test_no_persistant_comment_notif_on_revoke(self):
        from zds.tutorialv2.publication_utils import unpublish_content
        content = PublishedContentFactory(author_list=[self.user2])
        ContentReactionAnswerSubscription.objects.get_or_create_active(self.user1, content)
        ContentReactionFactory(related_content=content, author=self.user2, position=1)
        self.assertEqual(1, len(Notification.objects.get_unread_notifications_of(self.user1)))
        unpublish_content(content, moderator=self.user2)
        self.assertEqual(0, len(Notification.objects.get_unread_notifications_of(self.user1)))

    def test_only_one_notif_on_update(self):
        NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2)
        content = PublishedContentFactory(author_list=[self.user2])
        notify_update(content, False, True)
        versioned = content.load_version()
        content.sha_draft = versioned.repo_update(introduction='new intro', conclusion='new conclusion',
                                                  title=versioned.title)
        content.save(force_slug_update=False)
        publish_content(content, content.load_version(), True)
        notify_update(content, True, False)
        notifs = get_header_notifications(self.user1)['general_notifications']['list']
        self.assertEqual(1, len(notifs), str(notifs))

    def test_only_one_notif_on_major_update(self):
        NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2)
        content = PublishedContentFactory(author_list=[self.user2])
        notify_update(content, False, True)
        versioned = content.load_version()
        content.sha_draft = versioned.repo_update(introduction='new intro', conclusion='new conclusion',
                                                  title=versioned.title)
        content.save(force_slug_update=False)
        publish_content(content, content.load_version(), True)
        notify_update(content, True, True)
        notifs = get_header_notifications(self.user1)['general_notifications']['list']
        self.assertEqual(1, len(notifs), str(notifs))
Beispiel #57
0
class ContentTests(TutorialTestMixin, TestCase):
    def setUp(self):
        self.staff = StaffProfileFactory().user

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

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

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().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.subcategory.add(self.subcategory)
        self.tuto.save()

        self.beta_forum = ForumFactory(
            pk=self.overridden_zds_app['forum']['beta_forum_id'],
            category=CategoryFactory(position=1),
            position_in_category=1)  # ensure that the forum, for the beta versions, is created

        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.extract1 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
        bot = Group(name=self.overridden_zds_app['member']['bot_group'])
        bot.save()
        self.external = UserFactory(
            username=self.overridden_zds_app['member']['external_account'],
            password='******')

    def test_public_lists(self):
        tutorial = PublishedContentFactory(author_list=[self.user_author])
        tutorial_unpublished = PublishableContentFactory(author_list=[self.user_author])
        article = PublishedContentFactory(author_list=[self.user_author], type='ARTICLE')
        article_unpublished = PublishableContentFactory(author_list=[self.user_author], type='ARTICLE')
        self.client.logout()
        resp = self.client.get(reverse('publication:list') + '?type=tutorial')
        self.assertContains(resp, tutorial.title)
        self.assertNotContains(resp, tutorial_unpublished.title)
        resp = self.client.get(reverse('publication:list') + '?type=article')
        self.assertContains(resp, article.title)
        self.assertNotContains(resp, article_unpublished.title)
        resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk]) + '?filter=public')
        self.assertContains(resp, tutorial.title)
        self.assertNotContains(resp, tutorial_unpublished.title)
        resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk]) + '?filter=redaction')
        self.assertEqual(resp.status_code, 403)
        resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=public')
        self.assertContains(resp, article.title)
        self.assertNotContains(resp, article_unpublished.title)
        resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=redaction')
        self.assertEqual(resp.status_code, 403)
        resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=chuck-norris')
        self.assertEqual(resp.status_code, 404)

    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()
        publish_content(tuto_1, tuto_1_draft, is_major_update=True)

    def test_list_categories(self):
        category_1 = ContentCategoryFactory()
        subcategory_1 = SubCategoryFactory(category=category_1)
        subcategory_2 = SubCategoryFactory(category=category_1)
        # Not in context if nothing published inside this subcategory
        SubCategoryFactory(category=category_1)

        for _ in range(5):
            self._create_and_publish_type_in_subcategory('TUTORIAL', subcategory_1)
            self._create_and_publish_type_in_subcategory('ARTICLE', subcategory_2)

        self.client.logout()
        resp = self.client.get(reverse('publication:list'))

        context_categories = list(resp.context_data['categories'])
        self.assertEqual(context_categories[0].contents_count, 10)
        self.assertEqual(context_categories[0].subcategories, [subcategory_1, subcategory_2])
        self.assertEqual(context_categories, [category_1])

    def test_private_lists(self):
        tutorial = PublishedContentFactory(author_list=[self.user_author])
        tutorial_unpublished = PublishableContentFactory(author_list=[self.user_author])
        article = PublishedContentFactory(author_list=[self.user_author], type='ARTICLE')
        article_unpublished = PublishableContentFactory(author_list=[self.user_author], type='ARTICLE')
        self.client.login(
            username=self.user_author.username,
            password='******')
        resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk]))
        self.assertContains(resp, tutorial.title)
        self.assertContains(resp, tutorial_unpublished.title)
        self.assertContains(resp, 'content-illu')
        resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]))
        self.assertContains(resp, article.title)
        self.assertContains(resp, article_unpublished.title)
        self.assertContains(resp, 'content-illu')

    def test_validation_list(self):
        """ensure the behavior of the `validation:list` page (with filters)"""

        text = 'Ceci est un éléphant'

        tuto_not_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author])
        tuto_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author])
        article_not_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author])
        article_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author])

        all_contents = [tuto_not_reserved, tuto_reserved, article_not_reserved, article_reserved]
        reserved_contents = [tuto_reserved, article_reserved]

        # apply a filter to test category filter
        subcat = SubCategoryFactory()
        article_reserved.subcategory.add(subcat)
        article_reserved.save()

        # send in validation
        for content in all_contents:
            v = ValidationFactory(content=content, status='PENDING')
            v.date_proposition = datetime.datetime.now()
            v.version = content.sha_draft
            v.comment_authors = text

            if content in reserved_contents:
                v.validator = self.user_staff
                v.date_reserve = datetime.datetime.now()
                v.status = 'PENDING_V'

            v.save()

        # first, test access for public
        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 302)  # get 302 → redirection to login

        # connect with author:
        self.assertEqual(
            self.client.login(
                username=self.user_author.username,
                password='******'),
            True)

        result = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(result.status_code, 403)  # get 403 not allowed

        self.client.logout()

        # connect with staff:
        self.assertEqual(
            self.client.login(
                username=self.user_staff.username,
                password='******'),
            True)

        response = self.client.get(reverse('validation:list'), follow=False)
        self.assertEqual(response.status_code, 200)  # OK

        validations = response.context['validations']
        self.assertEqual(len(validations), 4)  # a total of 4 contents in validation

        # test filters
        response = self.client.get(reverse('validation:list') + '?type=article', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=tuto', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 articles

        response = self.client.get(reverse('validation:list') + '?type=orphan', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 not-reserved content

        for validation in validations:
            self.assertFalse(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') + '?type=reserved', follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 2)  # 2 reserved content

        for validation in validations:
            self.assertTrue(validation.content in reserved_contents)

        response = self.client.get(reverse('validation:list') + '?subcategory={}'.format(subcat.pk), follow=False)
        self.assertEqual(response.status_code, 200)  # OK
        validations = response.context['validations']
        self.assertEqual(len(validations), 1)  # 1 content with this category

        self.assertEqual(validations[0].content, article_reserved)  # the right content