def test_ensure_slug_stay(self): """This test ensures that slugs are not modified when coming from a manifest""" tuto = PublishableContentFactory(type='TUTORIAL') versioned = tuto.load_version() random = 'Non, piti bug, tu ne reviendras plus !!!' title = "N'importe quel titre" # add three container with the same title versioned.repo_add_container(title, random, random) # x versioned.repo_add_container(title, random, random) # x-1 version = versioned.repo_add_container(title, random, random) # x-2 self.assertEqual(len(versioned.children), 3) current = tuto.load_version(sha=version) self.assertEqual(len(current.children), 3) for index, child in enumerate(current.children): self.assertEqual(child.slug, versioned.children[index].slug) # same order # then, delete the second one: last_slug = versioned.children[2].slug version = versioned.children[1].repo_delete() self.assertEqual(len(versioned.children), 2) self.assertEqual(versioned.children[1].slug, last_slug) current = tuto.load_version(sha=version) self.assertEqual(len(current.children), 2) for index, child in enumerate(current.children): self.assertEqual(child.slug, versioned.children[index].slug) # slug remains # same test with extracts chapter = versioned.children[0] chapter.repo_add_extract(title, random) # x chapter.repo_add_extract(title, random) # x-1 version = chapter.repo_add_extract(title, random) # x-2 self.assertEqual(len(chapter.children), 3) current = tuto.load_version(sha=version) self.assertEqual(len(current.children[0].children), 3) for index, child in enumerate(current.children[0].children): self.assertEqual(child.slug, chapter.children[index].slug) # slug remains # delete the second one! last_slug = chapter.children[2].slug version = chapter.children[1].repo_delete() self.assertEqual(len(chapter.children), 2) self.assertEqual(chapter.children[1].slug, last_slug) current = tuto.load_version(sha=version) self.assertEqual(len(current.children[0].children), 2) for index, child in enumerate(current.children[0].children): self.assertEqual(child.slug, chapter.children[index].slug) # slug remains for extract as well!
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_ensure_slug_stay(self): """This test ensures that slugs are not modified when coming from a manifest""" tuto = PublishableContentFactory(type='TUTORIAL') versioned = tuto.load_version() random = 'Non, piti bug, tu ne reviendras plus !!!' title = "N'importe quel titre" # add three container with the same title versioned.repo_add_container(title, random, random) # x versioned.repo_add_container(title, random, random) # x-1 version = versioned.repo_add_container(title, random, random) # x-2 self.assertEqual(len(versioned.children), 3) current = tuto.load_version(sha=version) self.assertEqual(len(current.children), 3) for index, child in enumerate(current.children): self.assertEqual(child.slug, versioned.children[index].slug) # same order # then, delete the second one: last_slug = versioned.children[2].slug version = versioned.children[1].repo_delete() self.assertEqual(len(versioned.children), 2) self.assertEqual(versioned.children[1].slug, last_slug) current = tuto.load_version(sha=version) self.assertEqual(len(current.children), 2) for index, child in enumerate(current.children): self.assertEqual(child.slug, versioned.children[index].slug) # slug remains # same test with extracts chapter = versioned.children[0] chapter.repo_add_extract(title, random) # x chapter.repo_add_extract(title, random) # x-1 version = chapter.repo_add_extract(title, random) # x-2 self.assertEqual(len(chapter.children), 3) current = tuto.load_version(sha=version) self.assertEqual(len(current.children[0].children), 3) for index, child in enumerate(current.children[0].children): self.assertEqual(child.slug, chapter.children[index].slug) # slug remains # delete the second one! last_slug = chapter.children[2].slug version = chapter.children[1].repo_delete() self.assertEqual(len(chapter.children), 2) self.assertEqual(chapter.children[1].slug, last_slug) current = tuto.load_version(sha=version) self.assertEqual(len(current.children[0].children), 2) for index, child in enumerate(current.children[0].children): self.assertEqual(child.slug, chapter.children[index].slug) # slug remains for extract as well!
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_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_publish_content_big_tuto(self): # 4. Big tutorial: bigtuto = PublishableContentFactory(type='TUTORIAL') bigtuto.authors.add(self.user_author) UserGalleryFactory(gallery=bigtuto.gallery, user=self.user_author, mode='W') bigtuto.licence = self.licence bigtuto.save() # populate with 2 part (1 chapter with 1 extract each) bigtuto_draft = bigtuto.load_version() part1 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto) chapter1 = ContainerFactory(parent=part1, db_objet=bigtuto) ExtractFactory(container=chapter1, db_object=bigtuto) part2 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto) chapter2 = ContainerFactory(parent=part2, db_objet=bigtuto) ExtractFactory(container=chapter2, db_object=bigtuto) # publish it bigtuto = PublishableContent.objects.get(pk=bigtuto.pk) published = publish_content(bigtuto, bigtuto_draft) self.assertEqual(published.content, bigtuto) self.assertEqual(published.content_pk, bigtuto.pk) self.assertEqual(published.content_type, bigtuto.type) self.assertEqual(published.content_public_slug, bigtuto_draft.slug) self.assertEqual(published.sha_public, bigtuto.sha_draft) public = bigtuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(os.path.isdir(published.get_prod_path())) self.assertTrue(os.path.isfile(os.path.join(published.get_prod_path(), 'manifest.json'))) self.assertTrue(os.path.isfile(os.path.join(public.get_prod_path(), public.introduction))) self.assertTrue(os.path.isfile(os.path.join(public.get_prod_path(), public.conclusion))) self.assertEqual(len(public.children), 2) for part in public.children: self.assertTrue(os.path.isdir(part.get_prod_path())) # a directory for each part # ... and an HTML file for introduction and conclusion self.assertTrue(os.path.isfile(os.path.join(public.get_prod_path(), part.introduction))) self.assertTrue(os.path.isfile(os.path.join(public.get_prod_path(), part.conclusion))) self.assertEqual(len(part.children), 1) for chapter in part.children: # the HTML file is located in the good directory: self.assertEqual(part.get_prod_path(), os.path.dirname(chapter.get_prod_path())) self.assertTrue(os.path.isfile(chapter.get_prod_path())) # an HTML file for each chapter self.assertIsNone(chapter.introduction) self.assertIsNone(chapter.conclusion)
def test_image_with_non_ascii_chars(self): """seen on #4144""" article = PublishableContentFactory(type='article', author_list=[self.user_author]) image_string = '![Portrait de Richard Stallman en 2014. [Source](https://commons.wikimedia.org/wiki/' \ 'File:Richard_Stallman_-_Fête_de_l%27Humanité_2014_-_010.jpg).]' \ '(/media/galleries/4410/c1016bf1-a1de-48a1-9ef1-144308e8725d.jpg)' article.sha_draft = article.load_version().repo_update(article.title, image_string, '', update_slug=False) article.save(force_slug_update=False) publish_content(article, article.load_version()) self.assertTrue(PublishedContent.objects.filter(content_id=article.pk).exists())
def test_publish_content_medium_tuto(self): # 3. Medium-size tutorial midsize_tuto = PublishableContentFactory(type='TUTORIAL') midsize_tuto.authors.add(self.user_author) UserGalleryFactory(gallery=midsize_tuto.gallery, user=self.user_author, mode='W') midsize_tuto.licence = self.licence midsize_tuto.save() # populate with 2 chapters (1 extract each) midsize_tuto_draft = midsize_tuto.load_version() chapter1 = ContainerFactory(parent=midsize_tuto_draft, db_objet=midsize_tuto) ExtractFactory(container=chapter1, db_object=midsize_tuto) chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_objet=midsize_tuto) ExtractFactory(container=chapter2, db_object=midsize_tuto) # publish it midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk) published = publish_content(midsize_tuto, midsize_tuto_draft) self.assertEqual(published.content, midsize_tuto) self.assertEqual(published.content_pk, midsize_tuto.pk) self.assertEqual(published.content_type, midsize_tuto.type) self.assertEqual(published.content_public_slug, midsize_tuto_draft.slug) self.assertEqual(published.sha_public, midsize_tuto.sha_draft) public = midsize_tuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(Path(published.get_prod_path()).is_dir()) self.assertTrue( Path(published.get_prod_path(), 'manifest.json').is_file()) self.assertTrue( Path(public.get_prod_path(), public.introduction).is_file()) self.assertTrue( Path(public.get_prod_path(), public.conclusion).is_file()) self.assertEqual(len(public.children), 2) for child in public.children: self.assertTrue(os.path.isfile( child.get_prod_path())) # an HTML file for each chapter self.assertIsNone(child.introduction) self.assertIsNone(child.conclusion)
def test_image_with_non_ascii_chars(self): """seen on #4144""" article = PublishableContentFactory(type="article", author_list=[self.user_author]) image_string = ( "![Portrait de Richard Stallman en 2014. [Source](https://commons.wikimedia.org/wiki/" "File:Richard_Stallman_-_Fête_de_l%27Humanité_2014_-_010.jpg).]" "(/media/galleries/4410/c1016bf1-a1de-48a1-9ef1-144308e8725d.jpg)" ) article.sha_draft = article.load_version().repo_update(article.title, image_string, "", update_slug=False) article.save() publish_content(article, article.load_version()) self.assertTrue(PublishedContent.objects.filter(content_id=article.pk).exists())
def test_content_ordering(self): category_1 = ContentCategoryFactory() category_2 = ContentCategoryFactory() subcategory_1 = SubCategoryFactory(category=category_1) subcategory_1.position = 5 subcategory_1.save() subcategory_2 = SubCategoryFactory(category=category_1) subcategory_2.position = 1 subcategory_2.save() subcategory_3 = SubCategoryFactory(category=category_2) tuto_1 = PublishableContentFactory(type="TUTORIAL") tuto_1.subcategory.add(subcategory_1) tuto_1_draft = tuto_1.load_version() publish_content(tuto_1, tuto_1_draft, is_major_update=True) top_categories_tuto = topbar_publication_categories("TUTORIAL").get( "categories") expected = [(subcategory_1.title, subcategory_1.slug, category_1.slug)] self.assertEqual(top_categories_tuto[category_1.title], expected) tuto_2 = PublishableContentFactory(type="TUTORIAL") tuto_2.subcategory.add(subcategory_2) tuto_2_draft = tuto_2.load_version() publish_content(tuto_2, tuto_2_draft, is_major_update=True) top_categories_tuto = topbar_publication_categories("TUTORIAL").get( "categories") # New subcategory is now first is the list expected.insert( 0, (subcategory_2.title, subcategory_2.slug, category_1.slug)) self.assertEqual(top_categories_tuto[category_1.title], expected) article_1 = PublishableContentFactory(type="TUTORIAL") article_1.subcategory.add(subcategory_3) article_1_draft = tuto_2.load_version() publish_content(article_1, article_1_draft, is_major_update=True) # New article has no impact top_categories_tuto = topbar_publication_categories("TUTORIAL").get( "categories") self.assertEqual(top_categories_tuto[category_1.title], expected) top_categories_contents = topbar_publication_categories( ["TUTORIAL", "ARTICLE"]).get("categories") expected_2 = [(subcategory_3.title, subcategory_3.slug, category_2.slug)] self.assertEqual(top_categories_contents[category_1.title], expected) self.assertEqual(top_categories_contents[category_2.title], expected_2)
def testParseBadManifest(self): base_content = PublishableContentFactory(author_list=[self.user_author]) versioned = base_content.load_version() versioned.add_container(Container("un peu plus près de 42")) versioned.dump_json() manifest = os.path.join(versioned.get_path(), "manifest.json") dictionary = json_handler.load(open(manifest)) old_title = dictionary["title"] # first bad title dictionary["title"] = 81 * ["a"] self.assertRaises( BadManifestError, get_content_from_json, dictionary, None, "", max_title_len=PublishableContent._meta.get_field("title").max_length, ) dictionary["title"] = "".join(dictionary["title"]) self.assertRaises( BadManifestError, get_content_from_json, dictionary, None, "", max_title_len=PublishableContent._meta.get_field("title").max_length, ) dictionary["title"] = "..." self.assertRaises( InvalidSlugError, get_content_from_json, dictionary, None, "", max_title_len=PublishableContent._meta.get_field("title").max_length, ) dictionary["title"] = old_title dictionary["children"][0]["title"] = 81 * ["a"] self.assertRaises( BadManifestError, get_content_from_json, dictionary, None, "", max_title_len=PublishableContent._meta.get_field("title").max_length, ) dictionary["children"][0]["title"] = "bla" dictionary["children"][0]["slug"] = "..." self.assertRaises( InvalidSlugError, get_content_from_json, dictionary, None, "", max_title_len=PublishableContent._meta.get_field("title").max_length, )
def test_opinion_publication_guest(self): """ Test the publication of PublishableContent where type is OPINION (with guest => 403). """ text_publication = 'Aussi tôt dit, aussi tôt fait !' opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_guest.username, password='******'), True) result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'text': text_publication, 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 403) self.assertEqual(PublishedContent.objects.count(), 0)
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 testParseBadManifest(self): base_content = PublishableContentFactory(author_list=[self.user_author]) versioned = base_content.load_version() versioned.add_container(Container('un peu plus près de 42')) versioned.dump_json() manifest = os.path.join(versioned.get_path(), 'manifest.json') dictionary = json_handler.load(open(manifest)) old_title = dictionary['title'] # first bad title dictionary['title'] = 81 * ['a'] self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = ''.join(dictionary['title']) self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = '...' self.assertRaises(InvalidSlugError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = old_title dictionary['children'][0]['title'] = 81 * ['a'] self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['children'][0]['title'] = 'bla' dictionary['children'][0]['slug'] = '...' self.assertRaises(InvalidSlugError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length)
def test_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 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.login(username=author, password='******') # 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.login(username=user_staff.username, password='******') 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
class ContentNotification(TestCase): def setUp(self): self.user1 = ProfileFactory().user self.user2 = ProfileFactory().user # create a tutorial self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.user1) UserGalleryFactory(gallery=self.tuto.gallery, user=self.user1, mode='W') self.tuto.licence = LicenceFactory() self.tuto.subcategory.add(SubCategoryFactory()) self.tuto.save() tuto_draft = self.tuto.load_version() # then, publish it ! version = tuto_draft.current_version self.published = publish_content(self.tuto, tuto_draft, is_major_update=True) self.tuto.sha_public = version self.tuto.sha_draft = version self.tuto.public_version = self.published self.tuto.save() self.assertTrue(self.client.login(username=self.user1.username, password='******')) def test_no_persistant_notif_on_revoke(self): from zds.tutorialv2.publication_utils import unpublish_content NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2) content = PublishedContentFactory(author_list=[self.user2]) notif_signals.new_content.send(sender=self.tuto.__class__, instance=content, by_email=False) self.assertEqual(1, len(Notification.objects.get_notifications_of(self.user1))) unpublish_content(content) self.assertEqual(0, len(Notification.objects.get_notifications_of(self.user1)))
def testParseBadManifest(self): base_content = PublishableContentFactory(author_list=[self.user_author]) versioned = base_content.load_version() versioned.add_container(Container(u"un peu plus près de 42")) versioned.dump_json() manifest = os.path.join(versioned.get_path(), "manifest.json") dictionary = json_reader.load(open(manifest)) old_title = dictionary['title'] # first bad title dictionary['title'] = 81 * ['a'] self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = "".join(dictionary['title']) self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = '...' self.assertRaises(InvalidSlugError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['title'] = old_title dictionary['children'][0]['title'] = 81 * ['a'] self.assertRaises(BadManifestError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length) dictionary['children'][0]['title'] = "bla" dictionary['children'][0]['slug'] = "..." self.assertRaises(InvalidSlugError, get_content_from_json, dictionary, None, '', max_title_len=PublishableContent._meta.get_field('title').max_length)
def test_opinion_publication_guest(self): """ Test the publication of PublishableContent where type is OPINION (with guest => 403). """ text_publication = 'Aussi tôt dit, aussi tôt fait !' opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_guest.username, password='******'), True) result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'text': text_publication, 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 403) self.assertEqual(PublishedContent.objects.count(), 0)
def _create_and_publish_type_in_subcategory(self, content_type, subcategory): tuto_1 = PublishableContentFactory(type=content_type, author_list=[self.user_author]) tuto_1.subcategory.add(subcategory) tuto_1.save() tuto_1_draft = tuto_1.load_version() publish_content(tuto_1, tuto_1_draft, is_major_update=True)
def test_extract_is_none(self): """Test the case of a null extract""" article = PublishableContentFactory(type='ARTICLE') versioned = article.load_version() given_title = 'Peu importe, en fait, ça compte peu' some_text = 'Disparaitra aussi vite que possible' # add a new extract with `None` for text version = versioned.repo_add_extract(given_title, None) # check on the model: new_extract = versioned.children[-1] self.assertIsNone(new_extract.text) # it remains when loading the manifest! versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text) version = new_extract.repo_update(given_title, None) self.assertIsNone(new_extract.text) # it remains versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text) version = new_extract.repo_update(given_title, some_text) self.assertIsNotNone(new_extract.text) self.assertEqual(some_text, new_extract.get_text()) # now it changes versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNotNone(versioned.children[-1].text) # ... and lets go back version = new_extract.repo_update(given_title, None) self.assertIsNone(new_extract.text) # it has changed versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text)
def test_extract_is_none(self): """Test the case of a null extract""" article = PublishableContentFactory(type='ARTICLE') versioned = article.load_version() given_title = 'Peu importe, en fait, ça compte peu' some_text = 'Disparaitra aussi vite que possible' # add a new extract with `None` for text version = versioned.repo_add_extract(given_title, None) # check on the model: new_extract = versioned.children[-1] self.assertIsNone(new_extract.text) # it remains when loading the manifest! versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text) version = new_extract.repo_update(given_title, None) self.assertIsNone(new_extract.text) # it remains versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text) version = new_extract.repo_update(given_title, some_text) self.assertIsNotNone(new_extract.text) self.assertEqual(some_text, new_extract.get_text()) # now it changes versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNotNone(versioned.children[-1].text) # ... and lets go back version = new_extract.repo_update(given_title, None) self.assertIsNone(new_extract.text) # it has changed versioned2 = article.load_version(sha=version) self.assertIsNotNone(versioned2) self.assertIsNone(versioned.children[-1].text)
class ContentNotification(TestCase): def setUp(self): # don't build PDF to speed up the tests overridden_zds_app['content']['build_pdf_when_published'] = False self.user1 = ProfileFactory().user self.user2 = ProfileFactory().user # create a tutorial self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.user1) UserGalleryFactory(gallery=self.tuto.gallery, user=self.user1, mode='W') self.tuto.licence = LicenceFactory() self.tuto.subcategory.add(SubCategoryFactory()) self.tuto.save() tuto_draft = self.tuto.load_version() # then, publish it ! version = tuto_draft.current_version self.published = publish_content(self.tuto, tuto_draft, is_major_update=True) self.tuto.sha_public = version self.tuto.sha_draft = version self.tuto.public_version = self.published self.tuto.save() self.assertTrue( self.client.login(username=self.user1.username, password='******')) def test_no_persistant_notif_on_revoke(self): from zds.tutorialv2.publication_utils import unpublish_content NewPublicationSubscription.objects.get_or_create_active( self.user1, self.user2) content = PublishedContentFactory(author_list=[self.user2]) notif_signals.new_content.send(sender=self.tuto.__class__, instance=content, by_email=False) self.assertEqual( 1, len(Notification.objects.get_notifications_of(self.user1))) unpublish_content(content) self.assertEqual( 0, len(Notification.objects.get_notifications_of(self.user1))) def tearDown(self): if os.path.isdir(overridden_zds_app['content']['repo_private_path']): shutil.rmtree(overridden_zds_app['content']['repo_private_path']) if os.path.isdir(overridden_zds_app['content']['repo_public_path']): shutil.rmtree(overridden_zds_app['content']['repo_public_path']) if os.path.isdir(settings.MEDIA_ROOT): shutil.rmtree(settings.MEDIA_ROOT)
def test_publish_content_medium_tuto(self): # 3. Medium-size tutorial midsize_tuto = PublishableContentFactory(type='TUTORIAL') midsize_tuto.authors.add(self.user_author) UserGalleryFactory(gallery=midsize_tuto.gallery, user=self.user_author, mode='W') midsize_tuto.licence = self.licence midsize_tuto.save() # populate with 2 chapters (1 extract each) midsize_tuto_draft = midsize_tuto.load_version() chapter1 = ContainerFactory(parent=midsize_tuto_draft, db_objet=midsize_tuto) ExtractFactory(container=chapter1, db_object=midsize_tuto) chapter2 = ContainerFactory(parent=midsize_tuto_draft, db_objet=midsize_tuto) ExtractFactory(container=chapter2, db_object=midsize_tuto) # publish it midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk) published = publish_content(midsize_tuto, midsize_tuto_draft) self.assertEqual(published.content, midsize_tuto) self.assertEqual(published.content_pk, midsize_tuto.pk) self.assertEqual(published.content_type, midsize_tuto.type) self.assertEqual(published.content_public_slug, midsize_tuto_draft.slug) self.assertEqual(published.sha_public, midsize_tuto.sha_draft) public = midsize_tuto.load_version(sha=published.sha_public, public=published) self.assertIsNotNone(public) self.assertTrue(public.PUBLIC) # it's a PublicContent object self.assertEqual(public.type, published.content_type) self.assertEqual(public.current_version, published.sha_public) # test creation of files: self.assertTrue(Path(published.get_prod_path()).is_dir()) self.assertTrue(Path(published.get_prod_path(), 'manifest.json').is_file()) self.assertTrue(Path(public.get_prod_path(), public.introduction).is_file()) self.assertTrue(Path(public.get_prod_path(), public.conclusion).is_file()) self.assertEqual(len(public.children), 2) for child in public.children: self.assertTrue(os.path.isfile(child.get_prod_path())) # an HTML file for each chapter self.assertIsNone(child.introduction) self.assertIsNone(child.conclusion)
def test_content_ordering(self): category_1 = ContentCategoryFactory() category_2 = ContentCategoryFactory() subcategory_1 = SubCategoryFactory(category=category_1) subcategory_1.position = 5 subcategory_1.save() subcategory_2 = SubCategoryFactory(category=category_1) subcategory_2.position = 1 subcategory_2.save() subcategory_3 = SubCategoryFactory(category=category_2) tuto_1 = PublishableContentFactory(type='TUTORIAL') tuto_1.subcategory.add(subcategory_1) tuto_1_draft = tuto_1.load_version() publish_content(tuto_1, tuto_1_draft, is_major_update=True) top_categories_tuto = topbar_publication_categories('TUTORIAL').get('categories') expected = [(subcategory_1.title, subcategory_1.slug, category_1.slug)] self.assertEqual(top_categories_tuto[category_1.title], expected) tuto_2 = PublishableContentFactory(type='TUTORIAL') tuto_2.subcategory.add(subcategory_2) tuto_2_draft = tuto_2.load_version() publish_content(tuto_2, tuto_2_draft, is_major_update=True) top_categories_tuto = topbar_publication_categories('TUTORIAL').get('categories') # New subcategory is now first is the list expected.insert(0, (subcategory_2.title, subcategory_2.slug, category_1.slug)) self.assertEqual(top_categories_tuto[category_1.title], expected) article_1 = PublishableContentFactory(type='TUTORIAL') article_1.subcategory.add(subcategory_3) article_1_draft = tuto_2.load_version() publish_content(article_1, article_1_draft, is_major_update=True) # New article has no impact top_categories_tuto = topbar_publication_categories('TUTORIAL').get('categories') self.assertEqual(top_categories_tuto[category_1.title], expected) top_categories_contents = topbar_publication_categories(['TUTORIAL', 'ARTICLE']).get('categories') expected_2 = [(subcategory_3.title, subcategory_3.slug, category_2.slug)] self.assertEqual(top_categories_contents[category_1.title], expected) self.assertEqual(top_categories_contents[category_2.title], expected_2)
def test_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_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 create_multiple_tags(self, number_of_tags=REST_PAGE_SIZE): tags = [] for tag in range(0, number_of_tags): tags.append("number" + str(tag)) # Prepare content containing all the tags content = PublishableContentFactory(type="TUTORIAL") content.add_tags(tags) content.save() content_draft = content.load_version() # then, publish it ! publish_content(content, content_draft)
def create_multiple_tags(self, number_of_tags=REST_PAGE_SIZE): tags = [] for tag in range(0, number_of_tags): tags.append('number' + str(tag)) # Prepare content containing all the tags content = PublishableContentFactory(type='TUTORIAL') content.add_tags(tags) content.save() content_draft = content.load_version() # then, publish it ! publish_content(content, content_draft)
def 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 test_opinion_publication_author(self): """ Test the publication of PublishableContent where type is OPINION (with author). """ text_publication = "Aussi tôt dit, aussi tôt fait !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login(username=self.user_author.username, password="******"), True) result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version)
def test_collaborative_article_edition_and_editor_persistence(self): selenium = self.selenium find_element = selenium.find_element_by_css_selector author = ProfileFactory() article = PublishableContentFactory(type="ARTICLE", author_list=[author.user]) versioned_article = article.load_version() article.sha_draft = versioned_article.repo_update("article", "", "", update_slug=False) article.save() article_edit_url = reverse("content:edit", args=[article.pk, article.slug]) self.login(author) selenium.execute_script('localStorage.setItem("editor_choice", "new")' ) # we want the new editor selenium.get(self.live_server_url + article_edit_url) intro = find_element("div#div_id_introduction div.CodeMirror") # ActionChains: Support for CodeMirror https://stackoverflow.com/a/48969245/2226755 action_chains = ActionChains(selenium) scrollDriverTo(selenium, 0, 312) action_chains.click(intro).perform() action_chains.send_keys("intro").perform() output = "div#div_id_introduction div.CodeMirror div.CodeMirror-code" self.assertEqual("intro", find_element(output).text) article.sha_draft = versioned_article.repo_update("article", "new intro", "", update_slug=False) article.save() selenium.refresh() self.assertEqual( "new intro", find_element(".md-editor#id_introduction").get_attribute("value"))
def test_collaborative_article_edition_and_editor_persistence(self): selenium = self.selenium find_element = selenium.find_element_by_css_selector author = ProfileFactory() article = PublishableContentFactory(type='ARTICLE', author_list=[author.user]) versioned_article = article.load_version() article.sha_draft = versioned_article.repo_update('article', '', '', update_slug=False) article.save() article_edit_url = reverse('content:edit', args=[article.pk, article.slug]) self.login(author) selenium.get(self.live_server_url + article_edit_url) intro = find_element('.md-editor#id_introduction') intro.send_keys('intro') selenium.refresh() self.assertEqual( 'intro', find_element('.md-editor#id_introduction').get_attribute('value')) article.sha_draft = versioned_article.repo_update('article', 'new intro', '', update_slug=False) article.save() selenium.refresh() self.assertEqual( 'new intro', find_element('.md-editor#id_introduction').get_attribute('value'))
def test_opinion_publication_guest(self): """ Test the publication of PublishableContent where type is OPINION (with guest => 403). """ text_publication = "Aussi tôt dit, aussi tôt fait !" opinion = PublishableContentFactory(type="OPINION") opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode="W") opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.client.force_login(self.user_guest) result = self.client.post( reverse("validation:publish-opinion", kwargs={ "pk": opinion.pk, "slug": opinion.slug }), { "text": text_publication, "source": "", "version": opinion_draft.current_version }, follow=False, ) self.assertEqual(result.status_code, 403) self.assertEqual(PublishedContent.objects.count(), 0)
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_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_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 !
class NotificationPublishableContentTest(TestCase): def setUp(self): self.user1 = ProfileFactory().user self.user2 = ProfileFactory().user # create a tutorial self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.user1) UserGalleryFactory(gallery=self.tuto.gallery, user=self.user1, mode='W') self.tuto.licence = LicenceFactory() self.tuto.subcategory.add(SubCategoryFactory()) self.tuto.save() tuto_draft = self.tuto.load_version() # then, publish it ! version = tuto_draft.current_version self.published = publish_content(self.tuto, tuto_draft, is_major_update=True) self.tuto.sha_public = version self.tuto.sha_draft = version self.tuto.public_version = self.published self.tuto.save() self.assertTrue(self.client.login(username=self.user1.username, password='******')) def test_follow_content_at_publication(self): """ When a content is published, authors automatically follow it. """ subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertIsNone(subscription) # Signal call by the view at the publication. signals.new_content.send(sender=self.tuto.__class__, instance=self.tuto, by_email=False) subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertTrue(subscription.is_active) def test_follow_content_from_view(self): """ Allows a user to follow (or not) a content from the view. """ subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertIsNone(subscription) result = self.client.post(reverse('content:follow-reactions', args=[self.tuto.pk]), {'follow': 1}) self.assertEqual(result.status_code, 302) subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertTrue(subscription.is_active) result = self.client.post(reverse('content:follow-reactions', args=[self.tuto.pk]), {'follow': 0}) self.assertEqual(result.status_code, 302) subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertFalse(subscription.is_active) def test_answer_subscription(self): """ When a user posts on a publishable content, the user gets subscribed. """ subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertIsNone(subscription) result = self.client.post(reverse('content:add-reaction') + '?pk={}'.format(self.tuto.pk), { 'text': 'message', 'last_note': '0' }, follow=True) self.assertEqual(result.status_code, 200) subscription = ContentReactionAnswerSubscription.objects.get_existing(user=self.user1, content_object=self.tuto) self.assertTrue(subscription.is_active) def test_notification_read(self): """ When the notification is a reaction, it is marked as read when the corresponding content is displayed to the user. """ ContentReactionFactory(related_content=self.tuto, author=self.user1, position=1) last_note = ContentReactionFactory(related_content=self.tuto, author=self.user2, position=2) self.tuto.last_note = last_note self.tuto.save() notification = Notification.objects.get(subscription__user=self.user1) self.assertFalse(notification.is_read) result = self.client.get(reverse('tutorial:view', args=[self.tuto.pk, self.tuto.slug]), follow=False) self.assertEqual(result.status_code, 200) notification = Notification.objects.get(subscription__user=self.user1) self.assertTrue(notification.is_read) def test_subscription_to_new_publications_from_user(self): """ Any user may subscribe to new publications from a user. """ result = self.client.post(reverse('content:follow', args=[self.user1.pk]), follow=False) self.assertEqual(result.status_code, 403) self.client.logout() self.assertTrue(self.client.login(username=self.user2.username, password='******'), True) result = self.client.post(reverse('content:follow', args=[self.user1.pk]), { 'follow': 1 }, follow=False, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(result.status_code, 200) subscription = NewPublicationSubscription.objects.get_existing(user=self.user2, content_object=self.user1) self.assertTrue(subscription.is_active) result = self.client.post(reverse('content:follow', args=[self.user1.pk]), { 'email': 1 }, follow=False, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(result.status_code, 200) subscription = NewPublicationSubscription.objects.get_existing(user=self.user2, content_object=self.user1) self.assertTrue(subscription.is_active) self.assertTrue(subscription.by_email) def test_notification_generated_when_a_tuto_is_published(self): """ When a user subscribe to new publications from a user, a notification is generated when a publication is published. """ subscription = NewPublicationSubscription.objects.toggle_follow(self.user1, self.user2) signals.new_content.send(sender=self.tuto.__class__, instance=self.tuto, by_email=False) notifications = Notification.objects.filter(subscription=subscription, is_read=False).all() self.assertEqual(1, len(notifications)) signals.content_read.send(sender=self.tuto.__class__, instance=self.tuto, user=self.user2, target=ContentReaction) notifications = Notification.objects.filter(subscription=subscription, is_read=False).all() self.assertEqual(1, len(notifications)) signals.content_read.send(sender=self.tuto.__class__, instance=self.tuto, user=self.user2, target=PublishableContent) notifications = Notification.objects.filter(subscription=subscription, is_read=False).all() self.assertEqual(0, len(notifications)) def test_no_error_on_multiple_subscription(self): subscription = NewPublicationSubscription.objects.toggle_follow(self.user1, self.user2) signals.new_content.send(sender=self.tuto.__class__, instance=self.tuto, by_email=False) subscription1 = Notification.objects.filter(subscription=subscription, is_read=False).first() subscription2 = copy.copy(subscription1) subscription2.save() subscription.mark_notification_read(self.tuto) subscription1 = Notification.objects.filter(subscription=subscription, is_read=False).first() self.assertIsNone(subscription1) self.assertEqual(1, Notification.objects.filter(subscription=subscription, is_read=True).count())
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_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 _create_and_publish_type_in_subcategory(self, content_type, subcategory): tuto_1 = PublishableContentFactory(type=content_type, author_list=[self.user_author]) tuto_1.subcategory.add(subcategory) tuto_1.save() tuto_1_draft = tuto_1.load_version() publish_content(tuto_1, tuto_1_draft, is_major_update=True)
class ContentTests(TutorialTestMixin, TestCase): def setUp(self): self.staff = StaffProfileFactory().user settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' self.mas = ProfileFactory().user self.overridden_zds_app['member']['bot_account'] = self.mas.username self.licence = LicenceFactory() self.subcategory = SubCategoryFactory() self.user_author = ProfileFactory().user self.user_staff = StaffProfileFactory().user self.user_guest = ProfileFactory().user self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.user_author) UserGalleryFactory(gallery=self.tuto.gallery, user=self.user_author, mode='W') self.tuto.licence = self.licence self.tuto.subcategory.add(self.subcategory) self.tuto.save() self.beta_forum = ForumFactory( pk=self.overridden_zds_app['forum']['beta_forum_id'], category=CategoryFactory(position=1), position_in_category=1) # ensure that the forum, for the beta versions, is created self.tuto_draft = self.tuto.load_version() self.part1 = ContainerFactory(parent=self.tuto_draft, db_object=self.tuto) self.chapter1 = ContainerFactory(parent=self.part1, db_object=self.tuto) self.extract1 = ExtractFactory(container=self.chapter1, db_object=self.tuto) bot = Group(name=self.overridden_zds_app['member']['bot_group']) bot.save() self.external = UserFactory( username=self.overridden_zds_app['member']['external_account'], password='******') def test_public_lists(self): tutorial = PublishedContentFactory(author_list=[self.user_author]) tutorial_unpublished = PublishableContentFactory(author_list=[self.user_author]) article = PublishedContentFactory(author_list=[self.user_author], type='ARTICLE') article_unpublished = PublishableContentFactory(author_list=[self.user_author], type='ARTICLE') self.client.logout() resp = self.client.get(reverse('publication:list') + '?type=tutorial') self.assertContains(resp, tutorial.title) self.assertNotContains(resp, tutorial_unpublished.title) resp = self.client.get(reverse('publication:list') + '?type=article') self.assertContains(resp, article.title) self.assertNotContains(resp, article_unpublished.title) resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk]) + '?filter=public') self.assertContains(resp, tutorial.title) self.assertNotContains(resp, tutorial_unpublished.title) resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk]) + '?filter=redaction') self.assertEqual(resp.status_code, 403) resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=public') self.assertContains(resp, article.title) self.assertNotContains(resp, article_unpublished.title) resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=redaction') self.assertEqual(resp.status_code, 403) resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk]) + '?filter=chuck-norris') self.assertEqual(resp.status_code, 404) def _create_and_publish_type_in_subcategory(self, content_type, subcategory): tuto_1 = PublishableContentFactory(type=content_type, author_list=[self.user_author]) tuto_1.subcategory.add(subcategory) tuto_1.save() tuto_1_draft = tuto_1.load_version() publish_content(tuto_1, tuto_1_draft, is_major_update=True) def test_list_categories(self): category_1 = ContentCategoryFactory() subcategory_1 = SubCategoryFactory(category=category_1) subcategory_2 = SubCategoryFactory(category=category_1) # Not in context if nothing published inside this subcategory SubCategoryFactory(category=category_1) for _ in range(5): self._create_and_publish_type_in_subcategory('TUTORIAL', subcategory_1) self._create_and_publish_type_in_subcategory('ARTICLE', subcategory_2) self.client.logout() resp = self.client.get(reverse('publication:list')) context_categories = list(resp.context_data['categories']) self.assertEqual(context_categories[0].contents_count, 10) self.assertEqual(context_categories[0].subcategories, [subcategory_1, subcategory_2]) self.assertEqual(context_categories, [category_1]) def test_private_lists(self): tutorial = PublishedContentFactory(author_list=[self.user_author]) tutorial_unpublished = PublishableContentFactory(author_list=[self.user_author]) article = PublishedContentFactory(author_list=[self.user_author], type='ARTICLE') article_unpublished = PublishableContentFactory(author_list=[self.user_author], type='ARTICLE') self.client.login( username=self.user_author.username, password='******') resp = self.client.get(reverse('content:find-tutorial', args=[self.user_author.pk])) self.assertContains(resp, tutorial.title) self.assertContains(resp, tutorial_unpublished.title) self.assertContains(resp, 'content-illu') resp = self.client.get(reverse('content:find-article', args=[self.user_author.pk])) self.assertContains(resp, article.title) self.assertContains(resp, article_unpublished.title) self.assertContains(resp, 'content-illu') def test_validation_list(self): """ensure the behavior of the `validation:list` page (with filters)""" text = 'Ceci est un éléphant' tuto_not_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author]) tuto_reserved = PublishableContentFactory(type='TUTORIAL', author_list=[self.user_author]) article_not_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author]) article_reserved = PublishableContentFactory(type='ARTICLE', author_list=[self.user_author]) all_contents = [tuto_not_reserved, tuto_reserved, article_not_reserved, article_reserved] reserved_contents = [tuto_reserved, article_reserved] # apply a filter to test category filter subcat = SubCategoryFactory() article_reserved.subcategory.add(subcat) article_reserved.save() # send in validation for content in all_contents: v = ValidationFactory(content=content, status='PENDING') v.date_proposition = datetime.datetime.now() v.version = content.sha_draft v.comment_authors = text if content in reserved_contents: v.validator = self.user_staff v.date_reserve = datetime.datetime.now() v.status = 'PENDING_V' v.save() # first, test access for public result = self.client.get(reverse('validation:list'), follow=False) self.assertEqual(result.status_code, 302) # get 302 → redirection to login # connect with author: self.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) result = self.client.get(reverse('validation:list'), follow=False) self.assertEqual(result.status_code, 403) # get 403 not allowed self.client.logout() # connect with staff: self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) response = self.client.get(reverse('validation:list'), follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 4) # a total of 4 contents in validation # test filters response = self.client.get(reverse('validation:list') + '?type=article', follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 2) # 2 articles response = self.client.get(reverse('validation:list') + '?type=tuto', follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 2) # 2 articles response = self.client.get(reverse('validation:list') + '?type=orphan', follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 2) # 2 not-reserved content for validation in validations: self.assertFalse(validation.content in reserved_contents) response = self.client.get(reverse('validation:list') + '?type=reserved', follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 2) # 2 reserved content for validation in validations: self.assertTrue(validation.content in reserved_contents) response = self.client.get(reverse('validation:list') + '?subcategory={}'.format(subcat.pk), follow=False) self.assertEqual(response.status_code, 200) # OK validations = response.context['validations'] self.assertEqual(len(validations), 1) # 1 content with this category self.assertEqual(validations[0].content, article_reserved) # the right content
def test_opinion_alert(self): """Test content alert""" text_publication = 'Aussi tôt dit, aussi tôt fait !' opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'text': text_publication, 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # Alert content random_user = ProfileFactory().user self.assertEqual( self.client.login( username=random_user.username, password='******'), True) result = self.client.post( reverse('content:alert-content', kwargs={'pk': opinion.pk}), { 'signal_text': 'Yeurk !' }, follow=False ) self.assertEqual(result.status_code, 302) self.assertIsNotNone(Alert.objects.filter(author__pk=random_user.pk, content__pk=opinion.pk).first()) alert = Alert.objects.filter(author__pk=random_user.pk, content__pk=opinion.pk).first() self.assertFalse(alert.solved) result = self.client.post( reverse('content:resolve-content', kwargs={'pk': opinion.pk}), { 'alert_pk': alert.pk, 'text': 'Je peux ?' }, follow=False ) self.assertEqual(result.status_code, 403) # solving the alert by yourself wont work alert = Alert.objects.get(pk=alert.pk) self.assertFalse(alert.solved) self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) result = self.client.post( reverse('content:resolve-content', kwargs={'pk': opinion.pk}), { 'alert_pk': alert.pk, 'text': 'Anéfé!' }, follow=False ) self.assertEqual(result.status_code, 302) alert = Alert.objects.get(pk=alert.pk) self.assertTrue(alert.solved)
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.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'text': text_publication, 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # valid with author => 403 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.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) # 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.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) 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.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) 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_indexation(self): """test the indexation and deletion of the different documents""" if not self.manager.connected_to_es: return # create a topic with a post topic = TopicFactory(forum=self.forum, author=self.user) post = PostFactory(topic=topic, author=self.user, position=1) topic = Topic.objects.get(pk=topic.pk) post = Post.objects.get(pk=post.pk) self.assertFalse(topic.es_already_indexed) self.assertTrue(topic.es_flagged) self.assertFalse(post.es_already_indexed) self.assertTrue(post.es_flagged) # create a middle-tutorial and publish it tuto = PublishableContentFactory(type='TUTORIAL') tuto.authors.add(self.user) tuto.save() tuto_draft = tuto.load_version() chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto) ExtractFactory(container=chapter1, db_object=tuto) published = publish_content(tuto, tuto_draft, is_major_update=True) tuto.sha_public = tuto_draft.current_version tuto.sha_draft = tuto_draft.current_version tuto.public_version = published tuto.save() published = PublishedContent.objects.get(content_pk=tuto.pk) self.assertFalse(published.es_already_indexed) self.assertTrue(published.es_flagged) # 1. index all for model in self.indexable: if model is FakeChapter: continue self.manager.es_bulk_indexing_of_model(model, force_reindexing=False) self.manager.refresh_index() topic = Topic.objects.get(pk=topic.pk) post = Post.objects.get(pk=post.pk) self.assertTrue(topic.es_already_indexed) self.assertFalse(topic.es_flagged) self.assertTrue(post.es_already_indexed) self.assertFalse(post.es_flagged) published = PublishedContent.objects.get(content_pk=tuto.pk) self.assertTrue(published.es_already_indexed) self.assertFalse(published.es_flagged) s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 4) # get 4 results, one of each type must_contain = {'post': False, 'topic': False, 'publishedcontent': False, 'chapter': False} id_must_be = { 'post': str(post.pk), 'topic': str(topic.pk), 'publishedcontent': str(published.pk), 'chapter': tuto.slug + '__' + chapter1.slug } for hit in results: doc_type = hit.meta.doc_type must_contain[doc_type] = True self.assertEqual(hit.meta.id, id_must_be[doc_type]) self.assertTrue(all(must_contain)) # 2. Test what reindexation will do: new_topic = TopicFactory(forum=self.forum, author=self.user) new_post = PostFactory(topic=new_topic, author=self.user, position=1) pk_of_topics_to_reindex = [] for item in Topic.get_es_indexable(force_reindexing=False): pk_of_topics_to_reindex.append(item.pk) pk_of_posts_to_reindex = [] for item in Post.get_es_indexable(force_reindexing=False): pk_of_posts_to_reindex.append(item.pk) self.assertTrue(topic.pk not in pk_of_topics_to_reindex) self.assertTrue(new_topic.pk in pk_of_topics_to_reindex) self.assertTrue(post.pk not in pk_of_posts_to_reindex) self.assertTrue(new_post.pk in pk_of_posts_to_reindex) for model in self.indexable: # ok, so let's index that if model is FakeChapter: continue self.manager.es_bulk_indexing_of_model(model, force_reindexing=False) self.manager.refresh_index() s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 6) # good! # 3. Test single deletion: new_post = Post.objects.get(pk=new_post.pk) self.manager.delete_document(new_post) self.manager.refresh_index() s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 5) # one is missing for hit in results: self.assertTrue(hit.meta.doc_type != Post.get_es_document_type() or hit.meta.id != new_post.es_id) # 4. Test "delete_by_query_deletion": topic = Topic.objects.get(pk=topic.pk) new_topic = Topic.objects.get(pk=new_topic.pk) self.manager.delete_by_query(Topic.get_es_document_type(), MatchAll()) # the two topic are deleted self.manager.refresh_index() s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 3) for hit in results: self.assertTrue(hit.meta.doc_type != Topic.get_es_document_type() or hit.meta.id != new_topic.es_id) self.assertTrue(hit.meta.doc_type != Topic.get_es_document_type() or hit.meta.id != topic.es_id) # 5. Test that the deletion of an object also triggers its deletion in ES post = Post.objects.get(pk=post.pk) post.delete() self.manager.refresh_index() s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 2) for hit in results: self.assertTrue(hit.meta.doc_type != Post.get_es_document_type() or hit.meta.id != post.es_id) # 6. Test full desindexation: for model in self.indexable: if model is FakeChapter: continue self.manager.clear_indexing_of_model(model) # note "topic" is gone since "post" is gone, due to relationships at the Django level new_topic = Topic.objects.get(pk=new_topic.pk) new_post = Post.objects.get(pk=new_post.pk) self.assertFalse(new_topic.es_already_indexed) self.assertTrue(new_topic.es_flagged) self.assertFalse(new_post.es_already_indexed) self.assertTrue(new_post.es_flagged) published = PublishedContent.objects.get(content_pk=tuto.pk) self.assertFalse(published.es_already_indexed) self.assertTrue(published.es_flagged)
def test_special_case_of_contents(self): """test that the old publishedcontent does not stay when a new one is created""" if not self.manager.connected_to_es: return # 1. Create a middle-tutorial, publish it, then index it tuto = PublishableContentFactory(type='TUTORIAL') tuto.authors.add(self.user) tuto.save() tuto_draft = tuto.load_version() chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto) ExtractFactory(container=chapter1, db_object=tuto) published = publish_content(tuto, tuto_draft, is_major_update=True) tuto.sha_public = tuto_draft.current_version tuto.sha_draft = tuto_draft.current_version tuto.public_version = published tuto.save() self.manager.es_bulk_indexing_of_model(PublishedContent, force_reindexing=True) # index self.manager.refresh_index() first_publication = PublishedContent.objects.get(content_pk=tuto.pk) self.assertTrue(first_publication.es_already_indexed) self.assertFalse(first_publication.es_flagged) s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 2) # get 2 results, one for the content and one for the chapter self.assertEqual(PublishedContent.objects.count(), 1) # 2. Change thet title, which will trigger a change in the slug tuto = PublishableContent.objects.get(pk=tuto.pk) versioned = tuto.load_version(sha=tuto.sha_draft) tuto.title = 'un titre complètement différent!' tuto.save() versioned.repo_update_top_container(tuto.title, tuto.slug, 'osef', 'osef') second_publication = publish_content(tuto, versioned, True) tuto.sha_public = versioned.current_version tuto.sha_draft = versioned.current_version tuto.public_version = second_publication tuto.save() self.assertEqual(PublishedContent.objects.count(), 2) # now there is two objects ... first_publication = PublishedContent.objects.get(pk=first_publication.pk) self.assertTrue(first_publication.must_redirect) # .. including the first one, for redirection self.manager.refresh_index() s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 0) # the old one is gone (and we need to reindex to get the new one) # 3. Check if indexation brings the new one, and not the old one self.manager.es_bulk_indexing_of_model(PublishedContent, force_reindexing=True) # index self.manager.refresh_index() first_publication = PublishedContent.objects.get(pk=first_publication.pk) second_publication = PublishedContent.objects.get(pk=second_publication.pk) s = Search() s.query(MatchAll()) results = self.manager.setup_search(s).execute() self.assertEqual(len(results), 2) # Still 2, not 4 ! found_old = False found_new = False for hit in results: if hit.meta.doc_type == PublishedContent.get_es_document_type(): if hit.meta.id == first_publication.es_id: found_old = True if hit.meta.id == second_publication.es_id: found_new = True self.assertTrue(found_new) self.assertFalse(found_old)
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.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) # 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.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) # 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_boosts(self): """Check if boosts are doing their job""" if not self.manager.connected_to_es: return # 1. Create topics (with identical titles), posts (with identical texts), an article and a tuto text = 'test' topic_1_solved_sticky = TopicFactory(forum=self.forum, author=self.user) topic_1_solved_sticky.title = text topic_1_solved_sticky.subtitle = '' topic_1_solved_sticky.is_solved = True topic_1_solved_sticky.is_sticky = True topic_1_solved_sticky.save() post_1 = PostFactory(topic=topic_1_solved_sticky, author=self.user, position=1) post_1.text = post_1.text_html = text post_1.save() post_2_useful = PostFactory(topic=topic_1_solved_sticky, author=self.user, position=2) post_2_useful.text = post_2_useful.text_html = text post_2_useful.is_useful = True post_2_useful.like = 5 post_2_useful.dislike = 2 # l/d ratio above 1 post_2_useful.save() topic_2_locked = TopicFactory(forum=self.forum, author=self.user, title=text) topic_2_locked.title = text topic_2_locked.subtitle = '' topic_2_locked.is_locked = True topic_2_locked.save() post_3_ld_below_1 = PostFactory(topic=topic_2_locked, author=self.user, position=1) post_3_ld_below_1.text = post_3_ld_below_1.text_html = text post_3_ld_below_1.like = 2 post_3_ld_below_1.dislike = 5 # l/d ratio below 1 post_3_ld_below_1.save() tuto = PublishableContentFactory(type='TUTORIAL') tuto_draft = tuto.load_version() tuto.title = text tuto.authors.add(self.user) tuto.save() tuto_draft.repo_update_top_container(text, tuto.slug, text, text) chapter1 = ContainerFactory(parent=tuto_draft, db_object=tuto) chapter1.repo_update(text, 'Who cares ?', 'Same here') ExtractFactory(container=chapter1, db_object=tuto) published_tuto = publish_content(tuto, tuto_draft, is_major_update=True) tuto.sha_public = tuto_draft.current_version tuto.sha_draft = tuto_draft.current_version tuto.public_version = published_tuto tuto.save() article = PublishedContentFactory(type='ARTICLE', title=text) published_article = PublishedContent.objects.get(content_pk=article.pk) opinion_not_picked = PublishedContentFactory(type='OPINION', title=text) published_opinion_not_picked = PublishedContent.objects.get( content_pk=opinion_not_picked.pk) opinion_picked = PublishedContentFactory(type='OPINION', title=text) opinion_picked.sha_picked = opinion_picked.sha_draft opinion_picked.date_picked = datetime.datetime.now() opinion_picked.save() published_opinion_picked = PublishedContent.objects.get( content_pk=opinion_picked.pk) for model in self.indexable: if model is FakeChapter: continue self.manager.es_bulk_indexing_of_model(model) self.manager.refresh_index() self.assertEqual( len( self.manager.setup_search(Search().query( MatchAll())).execute()), 10) # 2. Reset all boosts to 1 for doc_type in settings.ZDS_APP['search']['boosts']: for key in settings.ZDS_APP['search']['boosts'][doc_type]: settings.ZDS_APP['search']['boosts'][doc_type][key] = 1.0 # 3. Test posts result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 3) # score are equals without boost: self.assertTrue(response[0].meta.score == response[1].meta.score == response[2].meta.score) settings.ZDS_APP['search']['boosts']['post']['if_first'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 3) self.assertTrue(response[0].meta.score == response[1].meta.score > response[2].meta.score) self.assertEqual(response[2].meta.id, str( post_2_useful.pk)) # post 2 is the only one not first settings.ZDS_APP['search']['boosts']['post']['if_first'] = 1.0 settings.ZDS_APP['search']['boosts']['post']['if_useful'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 3) self.assertTrue(response[0].meta.score > response[1].meta.score == response[2].meta.score) self.assertEqual(response[0].meta.id, str(post_2_useful.pk)) # post 2 is useful settings.ZDS_APP['search']['boosts']['post']['if_useful'] = 1.0 settings.ZDS_APP['search']['boosts']['post']['ld_ratio_above_1'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 3) self.assertTrue(response[0].meta.score > response[1].meta.score == response[2].meta.score) self.assertEqual(response[0].meta.id, str( post_2_useful.pk)) # post 2 have a l/d ratio of 5/2 settings.ZDS_APP['search']['boosts']['post']['ld_ratio_above_1'] = 1.0 settings.ZDS_APP['search']['boosts']['post'][ 'ld_ratio_below_1'] = 2.0 # no one would do that in real life result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 3) self.assertTrue(response[0].meta.score > response[1].meta.score == response[2].meta.score) self.assertEqual(response[0].meta.id, str( post_3_ld_below_1.pk)) # post 3 have a l/d ratio of 2/5 settings.ZDS_APP['search']['boosts']['post']['ld_ratio_below_1'] = 1.0 # 4. Test topics result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Topic.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 2) # score are equals without boost: self.assertTrue(response[0].meta.score == response[1].meta.score) settings.ZDS_APP['search']['boosts']['topic']['if_sticky'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Topic.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 2) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(topic_1_solved_sticky.pk)) # topic 1 is sticky settings.ZDS_APP['search']['boosts']['topic']['if_sticky'] = 1.0 settings.ZDS_APP['search']['boosts']['topic']['if_solved'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Topic.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 2) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(topic_1_solved_sticky.pk)) # topic 1 is solved settings.ZDS_APP['search']['boosts']['topic']['if_solved'] = 1.0 settings.ZDS_APP['search']['boosts']['topic'][ 'if_locked'] = 2.0 # no one would do that in real life result = self.client.get(reverse('search:query') + '?q=' + text + '&models=' + Topic.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 2) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(topic_2_locked.pk)) # topic 2 is locked settings.ZDS_APP['search']['boosts']['topic'][ 'if_locked'] = 1.0 # no one would do that in real life # 5. Test published contents result = self.client.get(reverse('search:query') + '?q=' + text + '&models=content', follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 5) # score are equals without boost: self.assertTrue( response[0].meta.score == response[1].meta.score == response[2]. meta.score == response[3].meta.score == response[4].meta.score) settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_article'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=content', follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 5) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(published_article.pk)) # obvious settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_article'] = 1.0 settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_tutorial'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=content', follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 5) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(published_tuto.pk)) # obvious settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_tutorial'] = 1.0 settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_opinion'] = 2.0 settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_opinion_not_picked'] = 4.0 # Note: in "real life", unpicked opinion would get a boost < 1. result = self.client.get(reverse('search:query') + '?q=' + text + '&models=content', follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 5) self.assertTrue(response[0].meta.score > response[1].meta.score > response[2].meta.score) self.assertEqual( response[0].meta.id, str(published_opinion_not_picked.pk)) # unpicked opinion got first self.assertEqual(response[1].meta.id, str(published_opinion_picked.pk)) settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_opinion'] = 1.0 settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_opinion_not_picked'] = 1.0 settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_medium_or_big_tutorial'] = 2.0 result = self.client.get(reverse('search:query') + '?q=' + text + '&models=content', follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 5) self.assertTrue(response[0].meta.score > response[1].meta.score) self.assertEqual(response[0].meta.id, str(published_tuto.pk)) # obvious settings.ZDS_APP['search']['boosts']['publishedcontent'][ 'if_medium_or_big_tutorial'] = 1.0 # 6. Test global boosts # NOTE: score are NOT the same for all documents, no matter how hard it tries to, small differences exists for model in self.indexable: # set a huge number to overcome the small differences: settings.ZDS_APP['search']['boosts'][ model.get_es_document_type()]['global'] = 10.0 result = self.client.get(reverse('search:query') + '?q=' + text, follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 10) self.assertEqual(response[0].meta.doc_type, model.get_es_document_type()) # obvious settings.ZDS_APP['search']['boosts'][ model.get_es_document_type()]['global'] = 1.0
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.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) # login as staff self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) # 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 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_defenitely_unpublish_alerted_opinion(self): opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) # login as staff self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) alerter = ProfileFactory().user Alert.objects.create(author=alerter, scope='CONTENT', content=opinion, pubdate=datetime.datetime.now(), text="J'ai un probleme avec cette opinion : c'est pas la mienne.") # unpublish opinion result = self.client.post( reverse('validation:ignore-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'operation': 'REMOVE_PUB', }, follow=False) self.assertEqual(result.status_code, 200) # refresh opinion = PublishableContent.objects.get(pk=opinion.pk) # check that the opinion is not published self.assertFalse(opinion.in_public()) # check that it's impossible to publish the opinion again result = self.client.get(opinion.get_absolute_url()) self.assertContains(result, _('Billet modéré')) # front result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 403) # back self.assertTrue(Alert.objects.filter(content=opinion).last().solved) # check alert page is still accessible and our alert is well displayed resp = self.client.get(reverse('pages-alerts')) self.assertEqual(200, resp.status_code) self.assertEqual(0, len(resp.context['alerts'])) self.assertEqual(1, len(resp.context['solved']))
def load_contents(cli, _type, size, fake): """Create v2 contents""" nb_contents = size * 10 percent_contents_in_validation = 0.4 percent_contents_with_validator = 0.2 percent_contents_public = 0.3 percent_mini = 0.5 percent_medium = 0.3 percent_big = 0.2 nb_avg_containers_in_content = size nb_avg_extracts_in_content = size is_articles = _type == "ARTICLE" is_tutorials = not is_articles textual_type = u"article" if is_tutorials: textual_type = u"tutoriel" # small introduction cli.stdout.write(u'À créer: {:d} {}s'.format(nb_contents, textual_type), ending='') if is_tutorials: cli.stdout.write(u' ({:g} petits, {:g} moyens et {:g} grands)' .format(nb_contents * percent_mini, nb_contents * percent_medium, nb_contents * percent_big)) else: cli.stdout.write('') cli.stdout.write( u' - {:g} en brouillon'.format( nb_contents * (1 - percent_contents_public - percent_contents_in_validation - percent_contents_with_validator))) cli.stdout.write( u' - {:g} en validation (dont {:g} réservés)' .format(nb_contents * (percent_contents_in_validation + percent_contents_with_validator), nb_contents * percent_contents_with_validator)) cli.stdout.write(u' - {:g} publiés'.format(nb_contents * percent_contents_public)) tps1 = time.time() # create tables with 0=draft, 1=in validation, 2=reserved, 3=published what_to_do = [] for i in range(nb_contents): what = 0 # in draft if i < percent_contents_public * nb_contents: what = 3 elif i < (percent_contents_public + percent_contents_with_validator) * nb_contents: what = 2 elif i >= (1 - percent_contents_in_validation) * nb_contents: what = 1 what_to_do.append(what) # create a table with 0=mini, 1=medium, 2=big content_sizes = [] for i in range(nb_contents): sz = 0 if i < percent_big * nb_contents: sz = 2 elif i >= (1 - percent_medium) * nb_contents: sz = 1 content_sizes.append(sz) # shuffle the whole thing random.shuffle(what_to_do) random.shuffle(content_sizes) # checks that everything is ok users = list(Profile.objects.all()) nb_users = len(users) sub_categories = list(SubCategory.objects.all()) nb_sub_categories = len(sub_categories) if nb_users == 0: cli.stdout.write(u"Il n'y a aucun membre actuellement. " u"Vous devez rajouter les membre dans vos fixtures (member)") return if nb_sub_categories == 0: cli.stdout.write(u"Il n'y a aucune catégories actuellement." u"Vous devez rajouter les catégories dans vos fixtures (category_content)") return perms = list(Permission.objects.filter(codename__startswith='change_').all()) staffs = list(User.objects.filter(groups__permissions__in=perms).all()) nb_staffs = len(staffs) if nb_staffs == 0: cli.stdout.write(u"Il n'y a aucun staff actuellement." u"Vous devez rajouter les staffs dans vos fixtures (staff)") return licenses = list(Licence.objects.all()) nb_licenses = len(licenses) if nb_licenses == 0: cli.stdout.write(u"Il n'y a aucune licence actuellement." u"Vous devez rajouter les licences dans vos fixtures (category_content)") return # create and so all: for i in range(nb_contents): sys.stdout.write("Création {} : {}/{} \r".format(textual_type, i + 1, nb_contents)) current_size = content_sizes[i] to_do = what_to_do[i] # creation: content = PublishableContentFactory( type=_type, title=fake.text(max_nb_chars=60), description=fake.sentence(nb_words=15, variable_nb_words=True)) versioned = content.load_version() if current_size == 0 or is_articles: for j in range(random.randint(1, nb_avg_extracts_in_content * 2)): ExtractFactory(container=versioned, title=fake.text(max_nb_chars=60), light=False) else: for j in range(random.randint(1, nb_avg_containers_in_content * 2)): container = ContainerFactory(parent=versioned, title=fake.text(max_nb_chars=60)) if current_size == 1: # medium size tutorial for k in range(random.randint(1, nb_avg_extracts_in_content * 2)): ExtractFactory(container=container, title=fake.text(max_nb_chars=60), light=False) else: # big-size tutorial for k in range(random.randint(1, nb_avg_containers_in_content * 2)): subcontainer = ContainerFactory(parent=container, title=fake.text(max_nb_chars=60)) for l in range(random.randint(1, nb_avg_extracts_in_content * 2)): ExtractFactory(container=subcontainer, title=fake.text(max_nb_chars=60), light=False) # add some informations: author = users[random.randint(0, nb_users - 1)].user content.authors.add(author) UserGalleryFactory(gallery=content.gallery, mode="W", user=author) content.licence = licenses[random.randint(0, nb_licenses - 1)] content.sha_draft = versioned.sha_draft content.subcategory.add(sub_categories[random.randint(0, nb_sub_categories - 1)]) content.save() # then, validation if needed: if to_do > 0: valid = CValidation( content=content, version=content.sha_draft, date_proposition=datetime.now(), status="PENDING") valid.comment_validator = fake.text(max_nb_chars=200) content.sha_validation = content.sha_draft if to_do > 1: # reserve validation valid.date_reserve = datetime.now() valid.validator = staffs[random.randint(0, nb_staffs - 1)] valid.status = "PENDING_V" if to_do > 2: # publish content valid.comment_validator = fake.text(max_nb_chars=80) valid.status = "ACCEPT" valid.date_validation = datetime.now() content.sha_public = content.sha_draft published = publish_content(content, versioned) content.public_version = published valid.save() content.save() sys.stdout.flush() tps2 = time.time() cli.stdout.write(u"\nFait en {:.3f} sec".format(tps2 - tps1))
def test_cancel_pick_operation(self): opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) # login as staff self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) # PICK result = self.client.post( reverse('validation:pick-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) # cancel the operation operation = PickListOperation.objects.latest('operation_date') result = self.client.post( reverse('validation:revoke-ignore-opinion', kwargs={'pk': operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # refresh operation = PickListOperation.objects.get(pk=operation.pk) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertFalse(operation.is_effective) self.assertEqual(self.user_staff, operation.canceler_user) self.assertIsNone(opinion.sha_picked) # NO_PICK result = self.client.post( reverse('validation:ignore-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'operation': 'NO_PICK', }, follow=False) self.assertEqual(result.status_code, 200) # cancel the operation operation = PickListOperation.objects.latest('operation_date') result = self.client.post( reverse('validation:revoke-ignore-opinion', kwargs={'pk': operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # check that the opinion is displayed on validation page result = self.client.get(reverse('validation:list-opinion')) self.assertContains(result, opinion.title) # REMOVE_PUB result = self.client.post( reverse('validation:ignore-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'operation': 'REMOVE_PUB', }, follow=False) self.assertEqual(result.status_code, 200) # cancel the operation operation = PickListOperation.objects.latest('operation_date') result = self.client.post( reverse('validation:revoke-ignore-opinion', kwargs={'pk': operation.pk}), follow=False) self.assertEqual(result.status_code, 200) # check that the opinion can be published again result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302)
class ContentNotification(TestCase, TutorialTestMixin): def setUp(self): # don't build PDF to speed up the tests self.user1 = ProfileFactory().user self.user2 = ProfileFactory().user # create a tutorial self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.user1) UserGalleryFactory(gallery=self.tuto.gallery, user=self.user1, mode='W') self.tuto.licence = LicenceFactory() self.tuto.subcategory.add(SubCategoryFactory()) self.tuto.save() tuto_draft = self.tuto.load_version() # then, publish it ! version = tuto_draft.current_version self.published = publish_content(self.tuto, tuto_draft, is_major_update=True) self.tuto.sha_public = version self.tuto.sha_draft = version self.tuto.public_version = self.published self.tuto.save() self.assertTrue(self.client.login(username=self.user1.username, password='******')) def test_no_persistant_notif_on_revoke(self): from zds.tutorialv2.publication_utils import unpublish_content NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2) content = PublishedContentFactory(author_list=[self.user2]) notif_signals.new_content.send(sender=self.tuto.__class__, instance=content, by_email=False) self.assertEqual(1, len(Notification.objects.get_notifications_of(self.user1))) unpublish_content(content) self.assertEqual(0, len(Notification.objects.get_notifications_of(self.user1))) def test_no_persistant_comment_notif_on_revoke(self): from zds.tutorialv2.publication_utils import unpublish_content content = PublishedContentFactory(author_list=[self.user2]) ContentReactionAnswerSubscription.objects.get_or_create_active(self.user1, content) ContentReactionFactory(related_content=content, author=self.user2, position=1) self.assertEqual(1, len(Notification.objects.get_unread_notifications_of(self.user1))) unpublish_content(content, moderator=self.user2) self.assertEqual(0, len(Notification.objects.get_unread_notifications_of(self.user1))) def test_only_one_notif_on_update(self): NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2) content = PublishedContentFactory(author_list=[self.user2]) notify_update(content, False, True) versioned = content.load_version() content.sha_draft = versioned.repo_update(introduction='new intro', conclusion='new conclusion', title=versioned.title) content.save(force_slug_update=False) publish_content(content, content.load_version(), True) notify_update(content, True, False) notifs = get_header_notifications(self.user1)['general_notifications']['list'] self.assertEqual(1, len(notifs), str(notifs)) def test_only_one_notif_on_major_update(self): NewPublicationSubscription.objects.get_or_create_active(self.user1, self.user2) content = PublishedContentFactory(author_list=[self.user2]) notify_update(content, False, True) versioned = content.load_version() content.sha_draft = versioned.repo_update(introduction='new intro', conclusion='new conclusion', title=versioned.title) content.save(force_slug_update=False) publish_content(content, content.load_version(), True) notify_update(content, True, True) notifs = get_header_notifications(self.user1)['general_notifications']['list'] self.assertEqual(1, len(notifs), str(notifs))
def test_opinion_conversion(self): """ Test the conversion of PublishableContent with type=OPINION to PublishableContent with type=ARTICLE """ text_publication = 'Aussi tôt dit, aussi tôt fait !' opinion = PublishableContentFactory(type='OPINION') opinion.authors.add(self.user_author) UserGalleryFactory(gallery=opinion.gallery, user=self.user_author, mode='W') opinion.licence = self.licence opinion.save() opinion_draft = opinion.load_version() ExtractFactory(container=opinion_draft, db_object=opinion) ExtractFactory(container=opinion_draft, db_object=opinion) self.assertEqual( self.client.login( username=self.user_author.username, password='******'), True) # publish result = self.client.post( reverse('validation:publish-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'text': text_publication, 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(PublishedContent.objects.count(), 1) opinion = PublishableContent.objects.get(pk=opinion.pk) self.assertIsNotNone(opinion.public_version) self.assertEqual(opinion.public_version.sha_public, opinion_draft.current_version) # valid with author => 403 result = self.client.post( reverse('validation:promote-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 403) self.assertEqual( self.client.login( username=self.user_staff.username, password='******'), True) # valid with staff result = self.client.post( reverse('validation:promote-opinion', kwargs={'pk': opinion.pk, 'slug': opinion.slug}), { 'source': '', 'version': opinion_draft.current_version }, follow=False) self.assertEqual(result.status_code, 302)