def setUp(self): self.overridden_zds_app = overridden_zds_app # don't build PDF to speed up the tests overridden_zds_app["content"]["build_pdf_when_published"] = False self.staff = StaffProfileFactory().user settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" self.mas = ProfileFactory().user overridden_zds_app["member"]["bot_account"] = self.mas.username self.licence = LicenceFactory() self.subcategory = SubCategoryFactory(category=CategoryFactory()) self.user_author = ProfileFactory().user self.user_staff = StaffProfileFactory().user self.user_guest = ProfileFactory().user self.content = PublishableContentFactory( author_list=[self.user_author], light=False) self.part_published = ContainerFactory( db_object=self.content, light=False, parent=self.content.load_version()) self.ignored_part = ContainerFactory( db_object=self.content, light=False, parent=self.content.load_version()) ExtractFactory(db_object=self.content, container=self.part_published, light=False) ExtractFactory(db_object=self.content, container=self.ignored_part, light=False)
def test_opinion_publication_staff(self): """ Test the publication of PublishableContent where type is OPINION (with staff). """ text_publication = "Aussi tôt dit, aussi tôt fait !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_staff) result = self.client.post( reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}), {"text": text_publication, "source": "", "version": opinion_draft.current_version}, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version)
def test_publish_content_medium_tuto(self): # 3. Medium-size tutorial midsize_tuto = PublishableContentFactory(type="TUTORIAL") midsize_tuto.authors.add(self.user_author) UserGalleryFactory(gallery=midsize_tuto.gallery, user=self.user_author, mode="W") midsize_tuto.licence = self.licence midsize_tuto.save() # populate with 2 chapters (1 extract each) midsize_tuto_draft = midsize_tuto.load_version() chapter1 = ContainerFactory(parent=midsize_tuto_draft, db_object=midsize_tuto) ExtractFactory(container=chapter1, db_object=midsize_tuto) chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_object=midsize_tuto) ExtractFactory(container=chapter2, db_object=midsize_tuto) # publish it midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk) published = publish_content(midsize_tuto, midsize_tuto_draft) self.assertEqual(published.content, midsize_tuto) self.assertEqual(published.content_pk, midsize_tuto.pk) self.assertEqual(published.content_type, midsize_tuto.type) self.assertEqual(published.content_public_slug, midsize_tuto_draft.slug) self.assertEqual(published.sha_public, midsize_tuto.sha_draft) public = midsize_tuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(Path(published.get_prod_path()).is_dir()) self.assertTrue( Path(published.get_prod_path(), "manifest.json").is_file()) self.assertTrue( Path(public.get_prod_path(), public.introduction).is_file()) self.assertTrue( Path(public.get_prod_path(), public.conclusion).is_file()) self.assertEqual(len(public.children), 2) for child in public.children: self.assertTrue(os.path.isfile( child.get_prod_path())) # an HTML file for each chapter self.assertIsNone(child.introduction) self.assertIsNone(child.conclusion)
def handle_content_with_chapter_and_parts( container, current_size, fake, nb_avg_containers_in_content, nb_avg_extracts_in_content ): 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 m in range(random.randint(1, nb_avg_extracts_in_content * 2)): ExtractFactory(container=subcontainer, title=fake.text(max_nb_chars=60), light=False)
def test_permanently_unpublish_opinion(self): opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}), {"source": "", "version": opinion_draft.current_version}, follow=False, ) self.assertEqual(result.status_code, 302) # login as staff self.client.force_login(self.user_staff) # unpublish opinion result = self.client.post( reverse("validation:ignore-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}), { "operation": "REMOVE_PUB", }, follow=False, ) self.assertEqual(result.status_code, 200) # refresh opinion = PublishableContent.objects.get(pk=opinion.pk) # check that the opinion is not published self.assertFalse(opinion.in_public()) # check that it's impossible to publish the opinion again result = self.client.get(opinion.get_absolute_url()) self.assertContains(result, _("Billet modéré")) # front result = self.client.post( reverse("validation:publish-opinion", kwargs={"pk": opinion.pk, "slug": opinion.slug}), {"source": "", "version": opinion_draft.current_version}, follow=False, ) self.assertEqual(result.status_code, 403) # back
def setUp(self): 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.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.extract1 = ExtractFactory(container=self.chapter1, db_object=self.tuto)
def setUp(self): self.overridden_zds_app = overridden_zds_app # don't build PDF to speed up the tests overridden_zds_app["content"]["build_pdf_when_published"] = False self.staff = StaffProfileFactory().user settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" self.mas = ProfileFactory().user overridden_zds_app["member"]["bot_account"] = self.mas.username bot = Group(name=overridden_zds_app["member"]["bot_group"]) bot.save() self.external = UserFactory( username=overridden_zds_app["member"]["external_account"], password="******") self.beta_forum = ForumFactory( pk=overridden_zds_app["forum"]["beta_forum_id"], category=ForumCategoryFactory(position=1), position_in_category=1, ) # ensure that the forum, for the beta versions, is created self.licence = LicenceFactory() self.subcategory = SubCategoryFactory() self.tag = TagFactory() self.user_author = ProfileFactory().user self.user_staff = StaffProfileFactory().user self.user_guest = ProfileFactory().user # 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.tags.add(self.tag) 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 = 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 self.article.save() self.articlefeed = LastArticlesFeedRSS()
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_ensure_unique_slug(self): """ Ensure that slugs for a container or extract are always unique """ # get draft version versioned = self.tuto.load_version() # forbidden slugs: slug_to_test = ["introduction", "conclusion"] for slug in slug_to_test: new_slug = versioned.get_unique_slug(slug) self.assertNotEqual(slug, new_slug) self.assertTrue( new_slug in versioned.slug_pool) # ensure new slugs are in slug pool # then test with 'real' containers and extracts: new_chapter_1 = ContainerFactory(title="aa", parent=versioned, db_object=self.tuto) new_chapter_2 = ContainerFactory(title="aa", parent=versioned, db_object=self.tuto) self.assertNotEqual(new_chapter_1.slug, new_chapter_2.slug) new_extract_1 = ExtractFactory(title="aa", container=new_chapter_1, db_object=self.tuto) self.assertEqual( new_extract_1.slug, new_chapter_1.slug) # different level can have the same slug! new_extract_2 = ExtractFactory(title="aa", container=new_chapter_2, db_object=self.tuto) self.assertEqual(new_extract_2.slug, new_extract_1.slug) # not the same parent, so allowed new_extract_3 = ExtractFactory(title="aa", container=new_chapter_1, db_object=self.tuto) self.assertNotEqual(new_extract_3.slug, new_extract_1.slug) # same parent, forbidden
def generate_text_for_content( current_size, fake, is_articles, is_opinion, nb_avg_containers_in_content, nb_avg_extracts_in_content, versioned ): if current_size == 0 or is_articles or is_opinion: for _ 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 _ in range(random.randint(1, nb_avg_containers_in_content * 2)): container = ContainerFactory(parent=versioned, title=fake.text(max_nb_chars=60)) handle_content_with_chapter_and_parts( container, current_size, fake, nb_avg_containers_in_content, nb_avg_extracts_in_content )
def test_mini_tuto(self): """ Test everything in a mini tuto is exported: + Content + Extract + Extract """ def check(path): with path.open("r") as f: content = f.read() self.assertIn(mini_tuto_draft.get_introduction(), content) self.assertIn(extract1.title, content) self.assertIn(extract1.get_text(), content) self.assertIn(extract2.title, content) self.assertIn(extract2.get_text(), content) self.assertIn(mini_tuto_draft.get_conclusion(), content) mini_tuto, mini_tuto_draft = self.create_content() extract1 = ExtractFactory(container=mini_tuto_draft, db_object=mini_tuto, title="Extract 1", text_content="Content extract 1") extract2 = ExtractFactory(container=mini_tuto_draft, db_object=mini_tuto, title="Extract 2", text_content="Content extract 2") # publish it published = publish_content(mini_tuto, mini_tuto_draft) # Test Markdown content: self.assertTrue(published.has_md()) check( Path(published.get_extra_contents_directory(), published.content_public_slug + ".md")) # PDF generation may fail, we only test the LaTeX content: check(Path(self.get_latex_file_path(published)))
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
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=ForumCategoryFactory(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_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_ignore_opinion(self): opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # ignore with author => 403 result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "NO_PICK", }, follow=False, ) self.assertEqual(result.status_code, 403) # now, login as staff self.client.force_login(self.user_staff) # check that the opinion is displayed result = self.client.get(reverse("validation:list-opinion")) self.assertContains(result, opinion.title) # ignore the opinion result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "NO_PICK", }, follow=False, ) self.assertEqual(result.status_code, 200) # check that the opinion is not displayed result = self.client.get(reverse("validation:list-opinion")) self.assertNotContains(result, opinion.title) # publish the opinion again result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # check that the opinion is displayed result = self.client.get(reverse("validation:list-opinion")) self.assertContains(result, opinion.title) # reject it result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "REJECT", }, follow=False, ) self.assertEqual(result.status_code, 200) # publish again result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # check that the opinion is not displayed result = self.client.get(reverse("validation:list-opinion")) self.assertNotContains(result, opinion.title)
def test_opinion_validation(self): """ Test the validation of PublishableContent where type is OPINION. """ text_publication = "Aussi tôt dit, aussi tôt fait !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # valid with author => 403 opinion = PublishableContent.objects.get(pk=opinion.pk) opinion_draft = opinion.load_version() result = self.client.post( reverse("validation:pick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNone(opinion.sha_picked) self.assertIsNone(opinion.picked_date) self.client.force_login(self.user_staff) # valid with staff result = self.client.post( reverse("validation:pick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertEqual(opinion.sha_picked, opinion_draft.current_version) self.assertIsNotNone(opinion.picked_date) # invalid with author => 403 self.client.force_login(self.user_author) result = self.client.post( reverse("validation:unpick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": "Parce que je veux", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertEqual(opinion.sha_picked, opinion_draft.current_version) # invalid with staff self.client.force_login(self.user_staff) result = self.client.post( reverse("validation:unpick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": "Parce que je peux !", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNone(opinion.sha_picked) # double invalidation wont work result = self.client.post( reverse("validation:unpick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": "Parce que je peux toujours ...", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403)
def test_opinion_unpublication(self, opinions_management): """ Test the unpublication of PublishableContent where type is OPINION (with author). """ text_publication = "Aussi tôt dit, aussi tôt fait !" text_unpublication = "Au revoir !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) # author self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) self.assertEqual(opinions_management.send.call_count, 1) self.assertEqual(opinions_management.send.call_args[1]["action"], "publish") opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # unpublish result = self.client.post( reverse("validation:unpublish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_unpublication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 0) self.assertEqual(opinions_management.send.call_count, 2) self.assertEqual(opinions_management.send.call_args[1]["action"], "unpublish") opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNone(opinion.public_version) # staff self.client.force_login(self.user_staff) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # unpublish result = self.client.post( reverse("validation:unpublish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_unpublication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 0) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNone(opinion.public_version) # guest => 403 self.client.force_login(self.user_author) # publish with author result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) self.client.force_login(self.user_guest) # unpublish result = self.client.post( reverse("validation:unpublish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_unpublication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403) self.assertEqual(PublishedContent.objects.count(), 1)
def test_opinion_alert(self): """Test content alert""" text_publication = "Aussi tôt dit, aussi tôt fait !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # Alert content random_user = ProfileFactory().user self.client.force_login(random_user) result = self.client.post(reverse("content:alert-content", kwargs={"pk": opinion.pk}), {"signal_text": "Yeurk !"}, follow=False) self.assertEqual(result.status_code, 302) self.assertIsNotNone( Alert.objects.filter(author__pk=random_user.pk, content__pk=opinion.pk).first()) alert = Alert.objects.filter(author__pk=random_user.pk, content__pk=opinion.pk).first() self.assertFalse(alert.solved) result = self.client.post( reverse("content:resolve-content", kwargs={"pk": opinion.pk}), { "alert_pk": alert.pk, "text": "Je peux ?" }, follow=False, ) self.assertEqual(result.status_code, 403) # solving the alert by yourself wont work alert = Alert.objects.get(pk=alert.pk) self.assertFalse(alert.solved) self.client.force_login(self.user_staff) result = self.client.post( reverse("content:resolve-content", kwargs={"pk": opinion.pk}), { "alert_pk": alert.pk, "text": "Anéfé!" }, follow=False, ) self.assertEqual(result.status_code, 302) alert = Alert.objects.get(pk=alert.pk) self.assertTrue(alert.solved)
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)
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
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_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
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_move_container_after(self): # login with author self.client.force_login(self.user_author) 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_export_only_ready_to_publish(self): """ Test exported contents contain only ready_to_publish==True parts. """ # We save the current settings for the PDF publicator: previous_pdf_publicator = PublicatorRegistry.get("pdf") previous_build_pdf_when_published = self.overridden_zds_app["content"][ "build_pdf_when_published"] # We need to produce at least the LaTeX file, so we use the real PDF publicator: PublicatorRegistry.registry["pdf"] = ZMarkdownRebberLatexPublicator( ".pdf") self.overridden_zds_app["content"]["build_pdf_when_published"] = True # Medium-size tutorial midsize_tuto = PublishableContentFactory(type="TUTORIAL") midsize_tuto.authors.add(self.user_author) UserGalleryFactory(gallery=midsize_tuto.gallery, user=self.user_author, mode="W") midsize_tuto.licence = self.licence midsize_tuto.save() # populate with 3 chapters (1 extract each), one not being ready for pubication midsize_tuto_draft = midsize_tuto.load_version() chapter1 = ContainerFactory(parent=midsize_tuto_draft, db_object=midsize_tuto, title="Chapter 1 ready") ExtractFactory(container=chapter1, db_object=midsize_tuto) chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_object=midsize_tuto, title="Chapter 2 ready") ExtractFactory(container=chapter2, db_object=midsize_tuto) chapter3 = ContainerFactory(parent=midsize_tuto_draft, db_object=midsize_tuto, title="Chapter 3 not ready") chapter3.ready_to_publish = False ExtractFactory(container=chapter3, db_object=midsize_tuto) # publish it midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk) published = publish_content(midsize_tuto, midsize_tuto_draft) public = midsize_tuto.load_version(sha=published.sha_public, public=published) # test creation of files: self.assertTrue(Path(published.get_prod_path()).is_dir()) self.assertTrue( Path(published.get_prod_path(), "manifest.json").is_file()) self.assertTrue( Path(public.get_prod_path(), public.introduction).is_file()) self.assertTrue( Path(public.get_prod_path(), public.conclusion).is_file()) self.assertEqual(len(public.children), 2) for child in public.children: self.assertTrue(os.path.isfile( child.get_prod_path())) # an HTML file for each chapter self.assertIsNone(child.introduction) self.assertIsNone(child.conclusion) # Test Markdown content: self.assertTrue(published.has_md()) with Path(published.get_extra_contents_directory(), published.content_public_slug + ".md").open("r") as md: content = md.read() self.assertIn(chapter1.title, content) self.assertIn(chapter2.title, content) self.assertNotIn(chapter3.title, content) # TODO: factorize getting the LaTeX file path with what is done in zds.tutorialv2.publication_utils.publish_content() tmp_path = os.path.join( settings.ZDS_APP["content"]["repo_public_path"], published.content_public_slug + "__building") build_extra_contents_path = os.path.join( tmp_path, settings.ZDS_APP["content"]["extra_contents_dirname"]) base_name = os.path.join(build_extra_contents_path, published.content_public_slug) tex_file = base_name + ".tex" # PDF generation may fail, we only test the LaTeX content: with open(tex_file) as tex: content = tex.read() self.assertIn(chapter1.title, content) self.assertIn(chapter2.title, content) self.assertNotIn(chapter3.title, content) # We set back the previous settings: PublicatorRegistry.registry["pdf"] = previous_pdf_publicator self.overridden_zds_app["content"][ "build_pdf_when_published"] = previous_build_pdf_when_published
def test_move_up_extract(self): # login with author self.client.force_login(self.user_author) 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.client.force_login(self.user_guest) 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_defenitely_unpublish_alerted_opinion(self): opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # login as staff self.client.force_login(self.user_staff) alerter = ProfileFactory().user Alert.objects.create( author=alerter, scope="CONTENT", content=opinion, pubdate=datetime.datetime.now(), text="J'ai un probleme avec cette opinion : c'est pas la mienne.", ) # unpublish opinion result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "REMOVE_PUB", }, follow=False, ) self.assertEqual(result.status_code, 200) # refresh opinion = PublishableContent.objects.get(pk=opinion.pk) # check that the opinion is not published self.assertFalse(opinion.in_public()) # check that it's impossible to publish the opinion again result = self.client.get(opinion.get_absolute_url()) self.assertContains(result, _("Billet modéré")) # front result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403) # back self.assertTrue(Alert.objects.filter(content=opinion).last().solved) # check alert page is still accessible and our alert is well displayed resp = self.client.get(reverse("pages-alerts")) self.assertEqual(200, resp.status_code) self.assertEqual(0, len(resp.context["alerts"])) self.assertEqual(1, len(resp.context["solved"]))
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
def test_cancel_pick_operation(self): opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_author) # publish result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # login as staff self.client.force_login(self.user_staff) # PICK result = self.client.post( reverse("validation:pick-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # cancel the operation operation = PickListOperation.objects.latest("operation_date") result = self.client.post(reverse("validation:revoke-ignore-opinion", kwargs={"pk": operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # refresh operation = PickListOperation.objects.get(pk=operation.pk) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertFalse(operation.is_effective) self.assertEqual(self.user_staff, operation.canceler_user) self.assertIsNone(opinion.sha_picked) # NO_PICK result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "NO_PICK", }, follow=False, ) self.assertEqual(result.status_code, 200) # cancel the operation operation = PickListOperation.objects.latest("operation_date") result = self.client.post(reverse("validation:revoke-ignore-opinion", kwargs={"pk": operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # check that the opinion is displayed on validation page result = self.client.get(reverse("validation:list-opinion")) self.assertContains(result, opinion.title) # REMOVE_PUB result = self.client.post( reverse("validation:ignore-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "operation": "REMOVE_PUB", }, follow=False, ) self.assertEqual(result.status_code, 200) # cancel the operation operation = PickListOperation.objects.latest("operation_date") result = self.client.post(reverse("validation:revoke-ignore-opinion", kwargs={"pk": operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # check that the opinion can be published again result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302)
def test_publish_content_big_tuto(self): # 4. Big tutorial: bigtuto = PublishableContentFactory(type="TUTORIAL") bigtuto.authors.add(self.user_author) UserGalleryFactory(gallery=bigtuto.gallery, user=self.user_author, mode="W") bigtuto.licence = self.licence bigtuto.save() # populate with 2 part (1 chapter with 1 extract each) bigtuto_draft = bigtuto.load_version() part1 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto) chapter1 = ContainerFactory(parent=part1, db_object=bigtuto) ExtractFactory(container=chapter1, db_object=bigtuto) part2 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto) chapter2 = ContainerFactory(parent=part2, db_object=bigtuto) ExtractFactory(container=chapter2, db_object=bigtuto) # publish it bigtuto = PublishableContent.objects.get(pk=bigtuto.pk) published = publish_content(bigtuto, bigtuto_draft) self.assertEqual(published.content, bigtuto) self.assertEqual(published.content_pk, bigtuto.pk) self.assertEqual(published.content_type, bigtuto.type) self.assertEqual(published.content_public_slug, bigtuto_draft.slug) self.assertEqual(published.sha_public, bigtuto.sha_draft) public = bigtuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(os.path.isdir(published.get_prod_path())) self.assertTrue( os.path.isfile( os.path.join(published.get_prod_path(), "manifest.json"))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), public.introduction))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), public.conclusion))) self.assertEqual(len(public.children), 2) for part in public.children: self.assertTrue(os.path.isdir( part.get_prod_path())) # a directory for each part # ... and an HTML file for introduction and conclusion self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), part.introduction))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), part.conclusion))) self.assertEqual(len(part.children), 1) for chapter in part.children: # the HTML file is located in the good directory: self.assertEqual(part.get_prod_path(), os.path.dirname(chapter.get_prod_path())) self.assertTrue(os.path.isfile( chapter.get_prod_path())) # an HTML file for each chapter self.assertIsNone(chapter.introduction) self.assertIsNone(chapter.conclusion)