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 get_small_opinion(self): """ Returns a published opinion without extract. """ opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = LicenceFactory() opinion.save() opinion_draft = opinion.load_version() return publish_content(opinion, opinion_draft)
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 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 create_content(self): """ Returns a content and its draft used in following tests. """ tuto = PublishableContentFactory(type="TUTORIAL", intro="Intro tuto", conclusion="Conclusion tuto") tuto.authors.add(self.user_author) UserGalleryFactory(gallery=tuto.gallery, user=self.user_author, mode="W") tuto.licence = self.licence tuto.save() tuto_draft = tuto.load_version() return tuto, tuto_draft
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_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_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_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 load_contents(cli, size, fake, _type, *_, **__): """Create v2 contents""" nb_contents = size * 10 percent_contents_in_validation = 0.2 percent_contents_with_validator = 0.1 percent_contents_public = 0.6 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 = _type == "TUTORIAL" is_opinion = _type == "OPINION" textual_type = "article" if is_tutorials: textual_type = "tutoriel" elif is_opinion: textual_type = "billet" # small introduction cli.stdout.write(f"À créer: {nb_contents:d} {textual_type}s", ending="") if is_tutorials: cli.stdout.write( " ({: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( " - {:g} en brouillon".format( nb_contents * (1 - percent_contents_public - percent_contents_in_validation - percent_contents_with_validator) ) ) if is_opinion: cli.stdout.write( " - {:g} publiés et {:g} approuvés en page d'accueil".format( nb_contents * (percent_contents_in_validation + percent_contents_with_validator), nb_contents * percent_contents_with_validator, ) ) else: cli.stdout.write( " - {: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(f" - {nb_contents * percent_contents_public:g} publiés") tps1 = time.time() # create tables with 0=draft, 1=in validation, 2=reserved, 3=published what_to_do = [] for created_content_index in range(nb_contents): what = 0 # in draft if created_content_index < percent_contents_public * nb_contents: what = 3 elif created_content_index < (percent_contents_public + percent_contents_with_validator) * nb_contents: what = 2 elif created_content_index >= (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 created_content_index in range(nb_contents): sz = 0 if created_content_index < percent_big * nb_contents: sz = 2 elif created_content_index >= (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( "Il n'y a aucun membre actuellement. " "Vous devez rajouter les membre dans vos fixtures (member)" ) return if nb_sub_categories == 0: cli.stdout.write( "Il n'y a aucune catégories actuellement." "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( "Il n'y a aucun staff actuellement." "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( "Il n'y a aucune licence actuellement." "Vous devez rajouter les licences dans vos fixtures (category_content)" ) return # create and so all: for created_content_index in range(nb_contents): sys.stdout.write(f"Création {textual_type} : {created_content_index + 1}/{nb_contents} \r") current_size = content_sizes[created_content_index] action_flag = what_to_do[created_content_index] # 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() generate_text_for_content( current_size, fake, is_articles, is_opinion, nb_avg_containers_in_content, nb_avg_extracts_in_content, versioned, ) # 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 action_flag > 0: if is_opinion: publish_opinion(content, action_flag, versioned) else: validate_edited_content(content, fake, nb_staffs, staffs, action_flag, versioned) sys.stdout.flush() tps2 = time.time() cli.stdout.write(f"\nFait en {tps2 - tps1:.3f} sec")
def test_publish_content_change_title_before_watchdog( self, opinions_management): """ Test we can publish a content, change its title and publish it again right away, before the publication watchdog processed the first publication. """ previous_extra_content_generation_policy = self.overridden_zds_app[ "content"]["extra_content_generation_policy"] self.overridden_zds_app["content"][ "extra_content_generation_policy"] = "WATCHDOG" # Create a content: opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() # Publish it a first time: self.client.force_login(self.user_author) result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": "Blabla", "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # Change the title: random = "Whatever, we don't care about the details" result = self.client.post( reverse("content:edit", args=[opinion.pk, opinion.slug]), { "title": "{} ({})".format(opinion.title, "modified"), "description": random, "introduction": random, "conclusion": random, "type": "OPINION", "licence": opinion.licence.pk, "subcategory": opinion.subcategory.first().pk, "last_hash": opinion.load_version().compute_hash(), "image": (settings.BASE_DIR / "fixtures" / "logo.png").open("rb"), }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) self.assertEqual(opinions_management.send.call_count, 1) self.assertEqual(opinions_management.send.call_args[1]["action"], "publish") opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # and publish it a second time now it has a new title: result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": "Blabla", "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) # There are two PublishedContent: one with the old title and the old slug # redirecting to the current version of the content with the new title: self.assertEqual(PublishedContent.objects.count(), 2) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) opinion_draft = opinion.load_version() self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) requested_events = PublicationEvent.objects.filter( state_of_processing="REQUESTED") self.assertEqual(requested_events.count(), 4) # Now, call the watchdog: call_command("publication_watchdog", "--once") requested_events = PublicationEvent.objects.filter( state_of_processing="REQUESTED") self.assertEqual(requested_events.count(), 0) self.overridden_zds_app["content"][ "extra_content_generation_policy"] = previous_extra_content_generation_policy
def test_publish_content_big_tuto(self): # 4. Big tutorial: bigtuto = PublishableContentFactory(type="TUTORIAL") bigtuto.authors.add(self.user_author) UserGalleryFactory(gallery=bigtuto.gallery, user=self.user_author, mode="W") bigtuto.licence = self.licence bigtuto.save() # populate with 2 part (1 chapter with 1 extract each) bigtuto_draft = bigtuto.load_version() part1 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto) chapter1 = ContainerFactory(parent=part1, db_object=bigtuto) ExtractFactory(container=chapter1, db_object=bigtuto) part2 = ContainerFactory(parent=bigtuto_draft, db_object=bigtuto) chapter2 = ContainerFactory(parent=part2, db_object=bigtuto) ExtractFactory(container=chapter2, db_object=bigtuto) # publish it bigtuto = PublishableContent.objects.get(pk=bigtuto.pk) published = publish_content(bigtuto, bigtuto_draft) self.assertEqual(published.content, bigtuto) self.assertEqual(published.content_pk, bigtuto.pk) self.assertEqual(published.content_type, bigtuto.type) self.assertEqual(published.content_public_slug, bigtuto_draft.slug) self.assertEqual(published.sha_public, bigtuto.sha_draft) public = bigtuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(os.path.isdir(published.get_prod_path())) self.assertTrue( os.path.isfile( os.path.join(published.get_prod_path(), "manifest.json"))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), public.introduction))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), public.conclusion))) self.assertEqual(len(public.children), 2) for part in public.children: self.assertTrue(os.path.isdir( part.get_prod_path())) # a directory for each part # ... and an HTML file for introduction and conclusion self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), part.introduction))) self.assertTrue( os.path.isfile( os.path.join(public.get_prod_path(), part.conclusion))) self.assertEqual(len(part.children), 1) for chapter in part.children: # the HTML file is located in the good directory: self.assertEqual(part.get_prod_path(), os.path.dirname(chapter.get_prod_path())) self.assertTrue(os.path.isfile( chapter.get_prod_path())) # an HTML file for each chapter self.assertIsNone(chapter.introduction) self.assertIsNone(chapter.conclusion)
def test_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_filters(self): """Test filtering by category & tag""" subcategory2 = SubCategoryFactory() subcategory3 = SubCategoryFactory() tag2 = TagFactory() tag3 = TagFactory() # Add a new tuto & publish it article2 = PublishableContentFactory(type="ARTICLE") article2.authors.add(self.user_author) article2.licence = self.licence article2.subcategory.add(subcategory2) article2.tags.add(self.tag) article2.tags.add(tag2) article2.save() article2_draft = article2.load_version() article2.sha_public = article2.sha_draft = article2_draft.current_version article2.public_version = publish_content(article2, article2_draft, is_major_update=True) article2.save() # Default view ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [article2, self.article]) # Filter by subcategory self.articlefeed.query_params = {"subcategory": self.subcategory.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [self.article]) self.articlefeed.query_params = { "subcategory": f" {self.subcategory.slug} " } ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [self.article]) self.articlefeed.query_params = {"subcategory": subcategory2.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [article2]) self.articlefeed.query_params = {"subcategory": subcategory3.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, []) self.articlefeed.query_params = {"subcategory": "invalid"} self.assertRaises(Http404, self.articlefeed.items) # Filter by tag self.articlefeed.query_params = {"tag": self.tag.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [article2, self.article]) self.articlefeed.query_params = {"tag": tag2.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [article2]) self.articlefeed.query_params = {"tag": f" {tag2.slug} "} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, [article2]) self.articlefeed.query_params = {"tag": tag3.slug} ret = [item.content for item in self.articlefeed.items()] self.assertEqual(ret, []) self.articlefeed.query_params = {"tag": "invalid"} self.assertRaises(Http404, self.articlefeed.items)