def test_hidden_forums_give_no_results_if_user_not_allowed(self): """Long name, isn't ?""" if not self.manager.connected_to_es: return # 1. Create a hidden forum belonging to a hidden staff group. text = 'test' group = Group.objects.create(name='Les illuminatis anonymes de ZdS') _, hidden_forum = create_category_and_forum(group) self.staff.groups.add(group) self.staff.save() topic_1 = TopicFactory(forum=hidden_forum, author=self.staff, title=text) post_1 = PostFactory(topic=topic_1, author=self.user, position=1) post_1.text = post_1.text_html = text post_1.save() self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) self.manager.refresh_index() self.assertEqual(len(self.manager.setup_search(Search().query(MatchAll())).execute()), 2) # indexing ok # 2. search without connection and get not result 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, 0) # 3. Connect with user (not a member of the group), search, and get no result self.assertTrue(self.client.login(username=self.user.username, password='******')) 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, 0) # 4. Connect with staff, search, and get the topic and the post self.client.logout() self.assertTrue(self.client.login(username=self.staff.username, password='******')) 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, 2) # ok !
def test_hidden_post_are_not_result(self): """Hidden posts should not show up in the search results""" 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() self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) self.manager.refresh_index() self.assertEqual(len(self.manager.setup_search(Search().query(MatchAll())).execute()), 2) # indexing ok post_1 = Post.objects.get(pk=post_1.pk) 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, 1) self.assertEqual(response[0].meta.id, post_1.es_id) # 2. Hide, reindex and search again: post_1.hide_comment_by_user(self.staff, 'Un abus de pouvoir comme un autre ;)') self.manager.refresh_index() 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, 0) # nothing in the results
def _prepare(cls, create, **kwargs): beta_forum = kwargs.pop("forum", None) publishable_content = super(BetaContentFactory, cls)._prepare(create, **kwargs) if publishable_content.authors.count() > 0 and beta_forum is not None: beta_topic = TopicFactory(title="[beta]" + publishable_content.title, author=publishable_content.authors.first(), forum=beta_forum) publishable_content.sha_beta = publishable_content.sha_draft publishable_content.beta_topic = beta_topic publishable_content.save() PostFactory(topic=beta_topic, position=1, author=publishable_content.authors.first()) beta_topic.save() return publishable_content
def test_get_active_alerts_count(self): # Start with 0 self.assertEqual(self.user1.get_active_alerts_count(), 0) # Post and Alert it ! post = PostFactory(topic=self.forumtopic, author=self.user1.user, position=1) Alert.objects.create(author=self.user1.user, comment=post, scope="FORUM", pubdate=datetime.now()) # Should be 1 self.assertEqual(self.user1.get_active_alerts_count(), 1)
def test_mark_read_a_topic_from_view_list_posts(self): """ To ensure we can subscribe to a topic, we first generate a new notification when another user posts a message, then mark the notification as read after displaying the list of messages. """ topic = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic, author=self.user2, position=1) # Follow the topic. self.assertIsNone( TopicAnswerSubscription.objects.get_existing(self.user1, topic)) subscription = TopicAnswerSubscription.objects.get_or_create_active( self.user1, topic) # Creates a new post in the topic to generate a new notification. PostFactory(topic=topic, author=self.user2, position=1) content_notification_type = ContentType.objects.get_for_model( topic.last_message) notification = Notification.objects.get( subscription=subscription, content_type__pk=content_notification_type.pk, object_id=topic.last_message.pk, is_read=False, ) self.assertIsNotNone(notification) response = self.client.get( reverse("topic-posts-list", args=[topic.pk, topic.slug()])) self.assertEqual(response.status_code, 200) # Checks that the notification is reading now. notification = Notification.objects.get( subscription=subscription, content_type__pk=content_notification_type.pk, object_id=topic.last_message.pk, is_read=True, ) self.assertIsNotNone(notification)
def load_topics(cli, size, fake): """ Load topics """ nb_topics = size * 10 cli.stdout.write(u"Nombres de Topics à créer : {}".format(nb_topics)) tps1 = time.time() nb_forums = Forum.objects.count() if nb_forums == 0: cli.stdout.write( u"Il n'y a aucun forum actuellement. " u"Vous devez rajouter les forums dans vos fixtures (forum)") else: forums = list(Forum.objects.all()) nb_users = User.objects.count() if nb_users == 0: cli.stdout.write( u"Il n'y a aucun membre actuellement. " u"Vous devez rajouter les membres dans vos fixtures (member)") else: profiles = list(Profile.objects.all()) nb_tags = Tag.objects.count() if nb_tags == 0: cli.stdout.write( u"Il n'y a aucun tag actuellement. " u"Vous devez rajouter les tags dans vos fixtures (tag)") else: for i in range(0, nb_topics): topic = TopicFactory(forum=forums[i % nb_forums], author=profiles[i % nb_users].user) if i % 5 == 0: topic.is_solved = True if i % 10 == 0: topic.is_locked = True if i % 15 == 0: topic.is_sticky = True nb_rand_tags = random.randint(0, 5) for k in range(0, nb_rand_tags): my_random_tag = Tag.objects.filter( pk=random.randint(1, nb_tags)).first() if my_random_tag: topic.tags.add(my_random_tag) topic.title = fake.text(max_nb_chars=80) topic.subtitle = fake.text(max_nb_chars=200) topic.save() PostFactory(topic=topic, author=topic.author, position=1) sys.stdout.write(" Topic {}/{} \r".format( i + 1, nb_topics)) sys.stdout.flush() tps2 = time.time() cli.stdout.write(u"\nFait en {} sec".format(tps2 - tps1))
def test_hide_post_mark_notification_as_read(self): """ Ensure a notification gets deleted when the corresponding post is hidden. """ topic = TopicFactory(forum=self.forum11, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) PostFactory(topic=topic, author=self.user2, position=2) PostFactory(topic=topic, author=ProfileFactory().user, position=3) notifications = Notification.objects.filter(object_id=topic.last_message.pk, is_read=False).all() self.assertEqual(1, len(notifications)) # hide last post data = { 'delete_message': '' } self.assertTrue(self.client.login(username=StaffProfileFactory().user.username, password='******')) response = self.client.post( reverse('post-edit') + '?message={}'.format(topic.last_message.pk), data, follow=False) self.assertEqual(302, response.status_code) notifications = Notification.objects.filter(object_id=topic.last_message.pk, is_read=True).all() self.assertEqual(1, len(notifications))
def _prepare(cls, create, **kwargs): author = kwargs.pop("author", None) beta_forum = kwargs.pop("forum", None) tuto = super(BetaMiniTutorialFactory, cls)._prepare(create, **kwargs) tuto.sha_beta = tuto.sha_draft if beta_forum is not None and author is not None: tuto.authors.add(author) tuto.save() beta_topic = TopicFactory(title="[beta]" + tuto.title, author=author, forum=beta_forum, key=tuto.pk) PostFactory(topic=beta_topic, position=1, author=author) beta_topic.key = tuto.pk beta_topic.save() return tuto
def test_mark_notifications_as_read(self): category = CategoryFactory(position=1) forum = ForumFactory(category=category, position_in_category=1) topic = TopicFactory(forum=forum, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) PostFactory(topic=topic, author=self.user2, position=2) self.assertTrue(self.client.login(username=self.user1.username, password='******')) notifications = Notification.objects.get_unread_notifications_of(self.user1) self.assertEqual(1, len(notifications)) self.assertFalse(is_read(topic, self.user1)) result = self.client.post( reverse('mark-notifications-as-read'), follow=False) self.assertEqual(result.status_code, 302) notifications = Notification.objects.get_unread_notifications_of(self.user1) self.assertEqual(0, len(notifications)) self.assertTrue(is_read(topic, self.user1))
def test_mark_all_notifications_as_read_when_toggle_follow(self): """ When a user unsubscribes from a content, we mark all notifications for this content as read. """ category = CategoryFactory(position=1) forum = ForumFactory(category=category, position_in_category=1) topic = TopicFactory(forum=forum, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) PostFactory(topic=topic, author=self.user2, position=2) notifications = Notification.objects.get_unread_notifications_of( self.user1) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) TopicAnswerSubscription.objects.toggle_follow(topic, self.user1) self.assertEqual( 0, len(Notification.objects.get_unread_notifications_of(self.user1)))
def test_get_similar_topics(self): """Get similar topics lists""" if not self.manager.connected_to_es: return text = 'Clem ne se mange pas' 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() text = 'Clem est la meilleure mascotte' topic_2 = TopicFactory(forum=self.forum, author=self.user, title=text) post_2 = PostFactory(topic=topic_2, author=self.user, position=1) post_2.text = post_1.text_html = text post_2.save() # 1. Should not get any result result = self.client.get(reverse('search:similar') + '?q=est', follow=False) self.assertEqual(result.status_code, 200) content = json.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 0) # index for model in self.indexable: if model is FakeChapter: continue self.manager.es_bulk_indexing_of_model(model) self.manager.refresh_index() # 2. Should get exactly one result result = self.client.get(reverse('search:similar') + '?q=mange', follow=False) self.assertEqual(result.status_code, 200) content = json.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 1) # 2. Should get exactly two results result = self.client.get(reverse('search:similar') + '?q=Clem', follow=False) self.assertEqual(result.status_code, 200) content = json.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 2)
def test_mark_notifications_as_read(self): category = ForumCategoryFactory(position=1) forum = ForumFactory(category=category, position_in_category=1) topic = TopicFactory(forum=forum, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) PostFactory(topic=topic, author=self.user2, position=2) self.client.force_login(self.user1) notifications = Notification.objects.get_unread_notifications_of( self.user1) self.assertEqual(1, len(notifications)) self.assertFalse(topic.is_read) result = self.client.post(reverse("mark-notifications-as-read"), follow=False) self.assertEqual(result.status_code, 302) notifications = Notification.objects.get_unread_notifications_of( self.user1) self.assertEqual(0, len(notifications)) self.assertTrue(Topic.objects.get(pk=topic.pk).is_read)
def test_edit_post(self): """To test all aspects of the edition of simple post by member.""" topic1 = TopicFactory(forum=self.forum11, author=self.user) post1 = PostFactory(topic=topic1, author=self.user, position=1) post2 = PostFactory(topic=topic1, author=self.user, position=2) post3 = PostFactory(topic=topic1, author=self.user, position=3) result = self.client.post(reverse( 'zds.forum.views.edit_post' ) + '?message={0}'.format(post2.pk), { 'text': u'C\'est tout simplement l\'histoire de la ville de Paris que je voudrais vous conter ' }, follow=False) self.assertEqual(result.status_code, 302) # check topic's number self.assertEqual(Topic.objects.all().count(), 1) # check post's number self.assertEqual(Post.objects.all().count(), 3) # check topic and post self.assertEqual(post1.topic, topic1) self.assertEqual(post2.topic, topic1) self.assertEqual(post3.topic, topic1) # check values self.assertEqual( Post.objects.get(pk=post2.pk).text, u'C\'est tout simplement l\'histoire de la ville de Paris que je voudrais vous conter ' ) # check edit data self.assertEqual(Post.objects.get(pk=post2.pk).editor, self.user)
def test_subscription_deactivated_and_notification_read_when_topic_moved( self): """ When a topic is moved to a forum where subscribers can't read it, the subscriptions should be deactivated and notifications marked as read. """ topic = TopicFactory(forum=self.forum11, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) PostFactory(topic=topic, author=ProfileFactory().user, position=2) self.assertIsNotNone( TopicAnswerSubscription.objects.get_existing(self.user1, topic, is_active=True)) self.assertIsNotNone( Notification.objects.get(subscription__user=self.user1, is_read=False)) forum_not_read = ForumFactory(category=self.category1, position_in_category=2) forum_not_read.group.add(Group.objects.create(name="DummyGroup_1")) self.assertTrue( self.client.login(username=StaffProfileFactory().user.username, password='******')) data = {'move': '', 'forum': forum_not_read.pk, 'topic': topic.pk} response = self.client.post(reverse('topic-edit'), data, follow=False) self.assertEqual(302, response.status_code) self.assertIsNotNone( TopicAnswerSubscription.objects.get_existing(self.user1, topic, is_active=False)) self.assertIsNotNone( Notification.objects.get(subscription__user=self.user1, is_read=True))
def test_success_post_karma_neutral(self): profile = ProfileFactory() category, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) another_profile = ProfileFactory() post = PostFactory(topic=topic, author=another_profile.user, position=2) vote = CommentVote(user=profile.user, comment=post, positive=True) vote.save() self.assertTrue(CommentVote.objects.filter(pk=vote.pk).exists()) self.assertTrue(self.client.login(username=profile.user.username, password='******')) response = self.client.put(reverse('api:forum:post-karma', args=(post.pk,)), {'vote': 'neutral'}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertFalse(CommentVote.objects.filter(pk=vote.pk).exists())
def test_failure_post_karma_with_sanctioned_user(self): profile = ProfileFactory() category, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) another_profile = ProfileFactory() post = PostFactory(topic=topic, author=another_profile.user, position=2) profile = ProfileFactory() profile.can_read = False profile.can_write = False profile.save() self.assertTrue(self.client.login(username=profile.user.username, password='******')) response = self.client.put(reverse('api:forum:post-karma', args=(post.pk,))) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_mark_read_a_topic_of_a_forum_subscribed(self): """ When a user has a notification on a topic, the notification should be marked as read. """ NewTopicSubscription.objects.toggle_follow(self.forum11, self.user1) topic = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic, author=self.user2, position=1) notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all() self.assertEqual(1, len(notifications)) response = self.client.get(reverse('topic-posts-list', args=[topic.pk, topic.slug()])) self.assertEqual(response.status_code, 200) notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all() self.assertEqual(0, len(notifications))
def test_success_post_karma_like_already_disliked(self): profile = ProfileFactory() category, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) another_profile = ProfileFactory() post = PostFactory(topic=topic, author=another_profile.user, position=2) vote = CommentVote(user=profile.user, comment=post, positive=False) vote.save() self.assertTrue(self.client.login(username=profile.user.username, password='******')) response = self.client.put(reverse('api:forum:post-karma', args=(post.pk,)), {'vote': 'like'}) vote.refresh_from_db() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue(vote.positive)
def test_answer_empty(self): """Test behaviour on empty answer.""" # Topic and 1st post by another user, to avoid antispam limitation topic1 = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic1, author=self.user2, position=1) result = self.client.post(reverse('zds.forum.views.answer') + '?sujet={0}'.format(topic1.pk), { 'last_post': topic1.last_message.pk, 'text': u' ' }, follow=False) # Empty text --> preview = HTTP 200 + post not saved (only 1 post in # topic) self.assertEqual(result.status_code, 200) self.assertEqual(Post.objects.filter(topic=topic1.pk).count(), 1)
def __generate_topic_and_post(cli, fake, nb_avg_posts_in_topic, nb_topics, nb_users, topics, tps1): profiles = list(Profile.objects.all()) for topic_index in range(0, nb_topics): nb_posts = randint(0, nb_avg_posts_in_topic * 2) + 1 for post_index in range(1, nb_posts): post = PostFactory(topic=topics[topic_index], author=profiles[post_index % nb_users].user, position=post_index + 1) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) post.is_useful = int(nb_posts * 0.3) > 0 and post_index % int(nb_posts * 0.3) == 0 post.save() sys.stdout.write(' Topic {}/{} \tPost {}/{} \r'.format(topic_index + 1, nb_topics, post_index + 1, nb_posts)) sys.stdout.flush() tps2 = time.time() cli.stdout.write('\nFait en {} sec'.format(tps2 - tps1))
def test_move_topic_from_forum_followed_to_forum_followed_too(self): NewTopicSubscription.objects.toggle_follow(self.forum11, self.user1) NewTopicSubscription.objects.toggle_follow(self.forum12, self.user1) topic = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic, author=self.user2, position=1) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=False).all())) # Move the topic to another forum. self.client.logout() staff = StaffProfileFactory() self.assertTrue( self.client.login(username=staff.user.username, password='******')) data = {'move': '', 'forum': self.forum12.pk, 'topic': topic.pk} response = self.client.post(reverse('topic-edit'), data, follow=False) self.assertEqual(302, response.status_code) topic = Topic.objects.get(pk=topic.pk) self.assertEqual(self.forum12, topic.forum) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=False, is_dead=False).all())) self.client.logout() self.assertTrue( self.client.login(username=self.user1.username, password='******')) response = self.client.get( reverse('topic-posts-list', args=[topic.pk, topic.slug()])) self.assertEqual(200, response.status_code) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=True, is_dead=False).all()))
def setUp(self): self.staff = StaffFactory() self.dummy_author = ProfileFactory() self.category = CategoryFactory(position=1) self.forum = ForumFactory(category=self.category, position_in_category=1) self.topic = TopicFactory(forum=self.forum, author=self.dummy_author.user) self.post = PostFactory(topic=self.topic, author=self.dummy_author.user, position=1) self.alerts = [] for i in range(20): alert = Alert(author=self.dummy_author.user, comment=self.post, scope='FORUM', text=u'pouet-{}'.format(i), pubdate=(datetime.now() + timedelta(minutes=i))) alert.save() self.alerts.append(alert)
def test_mark_as_potential_spam_forum(self): author = ProfileFactory() staff = StaffProfileFactory() _, forum = create_category_and_forum() topic = create_topic_in_forum(forum, author) PostFactory(topic=topic, author=author.user, position=2) comment = topic.last_message self.common_test_mark_as_potential_spam( url_comments_list=reverse("topic-posts-list", args=[topic.pk, topic.slug()]), url_comment_edit=reverse("post-edit") + f"?message={comment.pk}", comment=comment, author=author, staff=staff, )
def _generate(cls, create, attrs): # This parameter is only used inside _generate() and won't be saved in the database, # which is why we use attrs.pop() (it is removed from attrs). beta_forum = attrs.pop("forum", None) # Creates the PublishableContent (see PublishableContentFactory._generate() for more info) publishable_content = super()._generate(create, attrs) if publishable_content.authors.count() > 0 and beta_forum is not None: beta_topic = TopicFactory( title="[beta]" + publishable_content.title, author=publishable_content.authors.first(), forum=beta_forum ) publishable_content.sha_beta = publishable_content.sha_draft publishable_content.beta_topic = beta_topic publishable_content.save() PostFactory(topic=beta_topic, position=1, author=publishable_content.authors.first()) beta_topic.save() return publishable_content
def load_topics(cli, size, fake, *_, **__): """ Load topics """ nb_topics = size * 10 cli.stdout.write("Nombres de Topics à créer : {}".format(nb_topics)) tps1 = time.time() nb_forums = Forum.objects.count() if nb_forums == 0: cli.stdout.write( "Il n'y a aucun forum actuellement. " "Vous devez rajouter les forums dans vos fixtures (forum)") return forums = list(Forum.objects.all()) nb_users = User.objects.count() if nb_users == 0: cli.stdout.write( "Il n'y a aucun membre actuellement. " "Vous devez rajouter les membres dans vos fixtures (member)") return profiles = list(Profile.objects.all()) nb_tags = Tag.objects.count() if nb_tags == 0: cli.stdout.write( "Il n'y a aucun tag actuellement. " "Vous devez rajouter les tags dans vos fixtures (tag)") return for i in range(0, nb_topics): with contextlib.suppress(IntegrityError): topic = TopicFactory(forum=forums[i % nb_forums], author=profiles[i % nb_users].user) topic.solved_by = profiles[i % nb_users].user if i % 5 else None topic.is_locked = i % 10 == 0 topic.is_sticky = i % 15 == 0 nb_rand_tags = random.randint(0, 5) add_generated_tags_to_topic(nb_rand_tags, nb_tags, topic) topic.title = fake.text(max_nb_chars=80) topic.subtitle = fake.text(max_nb_chars=200) topic.save() PostFactory(topic=topic, author=topic.author, position=1) sys.stdout.write(" Topic {}/{} \r".format(i + 1, nb_topics)) sys.stdout.flush() tps2 = time.time() cli.stdout.write("\nFait en {} sec".format(tps2 - tps1))
def setUp(self): # prepare a user and 2 Topic (with and without tags) settings.EMAIL_BACKEND = \ 'django.core.mail.backends.locmem.EmailBackend' self.category1 = CategoryFactory(position=1) self.forum = ForumFactory( category=self.category1, position_in_category=1) self.forum2 = ForumFactory( category=self.category1, position_in_category=2) self.forum3 = ForumFactory( category=self.category1, position_in_category=3) self.user = ProfileFactory().user log = self.client.login( username=self.user.username, password='******') self.assertEqual(log, True) self.tag = TagFactory() self.topic1 = TopicFactory(forum=self.forum, author=self.user) self.topic2 = TopicFactory(forum=self.forum2, author=self.user) self.topic2.tags.add(self.tag) self.topic2.save() # create 2 posts un each forum PostFactory(topic=self.topic1, author=self.user, position=1) PostFactory(topic=self.topic1, author=self.user, position=2) PostFactory(topic=self.topic2, author=self.user, position=1) PostFactory(topic=self.topic2, author=self.user, position=2) # and last topic + post alone self.tag2 = TagFactory() self.topic3 = TopicFactory(forum=self.forum3, author=self.user) self.post3 = PostFactory(topic=self.topic3, author=self.user, position=1) self.topic3.tags.add(self.tag2) self.topic3.save() self.postfeed = LastPostsFeedRSS()
def test_add_subscribed_tag(self): """ When the topic is edited and a tag is added to which the user has subscribed """ NewTopicSubscription.objects.toggle_follow(self.tag1, self.user2) topic = TopicFactory(forum=self.forum11, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) self.client.post( reverse('topic-edit') + '?topic={0}'.format(topic.pk), { 'title': 'Un autre sujet', 'subtitle': 'Encore ces lombards en plein ete', 'text': 'C\'est tout simplement l\'histoire de la ville de Paris que je voudrais vous conter ', 'tags': 'Linux' }, follow=False) notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all() self.assertEqual(1, len(notifications))
def test_success_post_karma_dislike(self): profile = ProfileFactory() category, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) another_profile = ProfileFactory() post = PostFactory(topic=topic, author=another_profile.user, position=2) self.assertTrue( self.client.login(username=profile.user.username, password="******")) response = self.client.put( reverse("api:forum:post-karma", args=(post.pk, )), {"vote": "dislike"}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue( CommentVote.objects.filter(user=profile.user, comment=post, positive=False).exists())
def test_move_topic_from_forum_followed_to_forum_followed_too(self): NewTopicSubscription.objects.toggle_follow(self.forum11, self.user1) NewTopicSubscription.objects.toggle_follow(self.forum12, self.user1) topic = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic, author=self.user2, position=1) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=False).all())) # Move the topic to another forum. self.client.logout() staff = StaffProfileFactory() self.client.force_login(staff.user) data = {"move": "", "forum": self.forum12.pk, "topic": topic.pk} response = self.client.post(reverse("topic-edit"), data, follow=False) self.assertEqual(302, response.status_code) topic = Topic.objects.get(pk=topic.pk) self.assertEqual(self.forum12, topic.forum) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=False, is_dead=False).all())) self.client.logout() self.client.force_login(self.user1) response = self.client.get( reverse("topic-posts-list", args=[topic.pk, topic.slug()])) self.assertEqual(200, response.status_code) self.assertEqual( 1, len( Notification.objects.filter(object_id=topic.pk, is_read=True, is_dead=False).all()))
def test_hidden_post_are_not_result(self): """Hidden posts should not show up in the search results""" 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() self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) self.manager.refresh_index() self.assertEqual( len( self.manager.setup_search(Search().query( MatchAll())).execute()), 2) # indexing ok post_1 = Post.objects.get(pk=post_1.pk) 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, 1) self.assertEqual(response[0].meta.id, post_1.es_id) # 2. Hide, reindex and search again: post_1.hide_comment_by_user(self.staff, 'Un abus de pouvoir comme un autre ;)') self.manager.refresh_index() 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, 0) # nothing in the results
def load_posts(cli, size, fake): """ Load posts """ nb_avg_posts_in_topic = size * 20 cli.stdout.write( u"Nombres de messages à poster en moyenne dans un sujet : {}".format( nb_avg_posts_in_topic)) tps1 = time.time() nb_topics = Topic.objects.count() if nb_topics == 0: cli.stdout.write( u"Il n'y a aucun topic actuellement. " u"Vous devez rajouter les topics dans vos fixtures (topic)") else: topics = list(Topic.objects.all()) nb_users = User.objects.count() if nb_users == 0: cli.stdout.write( u"Il n'y a aucun membre actuellement. " u"Vous devez rajouter les membres dans vos fixtures (member)") else: profiles = list(Profile.objects.all()) for i in range(0, nb_topics): nb_posts = randint(0, nb_avg_posts_in_topic * 2) + 1 for j in range(1, nb_posts): post = PostFactory(topic=topics[i], author=profiles[j % nb_users].user, position=j + 1) post.text = fake.paragraph(nb_sentences=5, variable_nb_sentences=True) post.text_html = emarkdown(post.text) if int(nb_posts * 0.3) > 0: if j % int(nb_posts * 0.3) == 0: post.is_useful = True post.save() sys.stdout.write(" Topic {}/{} \tPost {}/{} \r".format( i + 1, nb_topics, j + 1, nb_posts)) sys.stdout.flush() tps2 = time.time() cli.stdout.write(u"\nFait en {} sec".format(tps2 - tps1))
def test_notification_read(self): """ When we post on a topic, a notification is created for each subscriber. We can read a notification when we display the list of messages of the said topic. """ topic1 = TopicFactory(forum=self.forum11, author=self.user2) PostFactory(topic=topic1, author=self.user2, position=1) result = self.client.post( reverse("post-new") + "?sujet={0}".format(topic1.pk), { "last_post": topic1.last_message.pk, "text": "C'est tout simplement l'histoire de la ville de Paris que je voudrais vous conter ", }, follow=False, ) self.assertEqual(result.status_code, 302) notification = Notification.objects.get(subscription__user=self.user2) self.assertEqual(notification.is_read, False) self.client.logout() self.assertTrue( self.client.login(username=self.user2.username, password="******"), True) result = self.client.get(reverse( "topic-posts-list", args=[topic1.pk, old_slugify(topic1.title)]), follow=True) self.assertEqual(result.status_code, 200) notification = Notification.objects.get(subscription__user=self.user2) self.assertEqual(notification.is_read, True)
def test_get_similar_topics(self): """Get similar topics lists""" if not self.manager.connected_to_es: return text = 'Clem ne se mange pas' 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() text = 'Clem est la meilleure mascotte' topic_2 = TopicFactory(forum=self.forum, author=self.user, title=text) post_2 = PostFactory(topic=topic_2, author=self.user, position=1) post_2.text = post_1.text_html = text post_2.save() # 1. Should not get any result result = self.client.get(reverse('search:similar') + '?q=est', follow=False) self.assertEqual(result.status_code, 200) content = json_handler.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 0) # index for model in self.indexable: if model is FakeChapter: continue self.manager.es_bulk_indexing_of_model(model) self.manager.refresh_index() # 2. Should get exactly one result result = self.client.get(reverse('search:similar') + '?q=mange', follow=False) self.assertEqual(result.status_code, 200) content = json_handler.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 1) # 2. Should get exactly two results result = self.client.get(reverse('search:similar') + '?q=Clem', follow=False) self.assertEqual(result.status_code, 200) content = json_handler.loads(result.content.decode('utf-8')) self.assertEqual(len(content['results']), 2)
def test_add_subscribed_tag(self): """ When the topic is edited and a tag is added to which the user has subscribed """ NewTopicSubscription.objects.toggle_follow(self.tag1, self.user2) topic = TopicFactory(forum=self.forum11, author=self.user1) PostFactory(topic=topic, author=self.user1, position=1) self.client.post( reverse("topic-edit") + f"?topic={topic.pk}", { "title": "Un autre sujet", "subtitle": "Encore ces lombards en plein ete", "text": "C'est tout simplement l'histoire de la ville de Paris que je voudrais vous conter ", "tags": "Linux", }, follow=False, ) notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all() self.assertEqual(1, len(notifications))
def test_get_post_voters(self): profile = ProfileFactory() profile2 = ProfileFactory() category, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) another_profile = ProfileFactory() upvoted_answer = PostFactory(topic=topic, author=another_profile.user, position=2) upvoted_answer.like += 2 upvoted_answer.save() CommentVote.objects.create(user=profile.user, comment=upvoted_answer, positive=True) downvoted_answer = PostFactory(topic=topic, author=another_profile.user, position=3) downvoted_answer.dislike += 2 downvoted_answer.save() anon_limit = CommentVote.objects.create(user=profile.user, comment=downvoted_answer, positive=False) CommentVote.objects.create(user=profile2.user, comment=upvoted_answer, positive=True) CommentVote.objects.create(user=profile2.user, comment=downvoted_answer, positive=False) equal_answer = PostFactory(topic=topic, author=another_profile.user, position=4) equal_answer.like += 1 equal_answer.dislike += 1 equal_answer.save() CommentVote.objects.create(user=profile.user, comment=equal_answer, positive=True) CommentVote.objects.create(user=profile2.user, comment=equal_answer, positive=False) self.assertTrue(self.client.login(username=profile.user.username, password='******')) # on first message we should see 2 likes and 0 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[upvoted_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(2, len(response.data['like']['users'])) self.assertEqual(0, len(response.data['dislike']['users'])) self.assertEqual(2, response.data['like']['count']) self.assertEqual(0, response.data['dislike']['count']) # on second message we should see 2 dislikes and 0 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[downvoted_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(0, len(response.data['like']['users'])) self.assertEqual(2, len(response.data['dislike']['users'])) self.assertEqual(0, response.data['like']['count']) self.assertEqual(2, response.data['dislike']['count']) # on third message we should see 1 like and 1 dislike and 0 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[equal_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(1, len(response.data['like']['users'])) self.assertEqual(1, len(response.data['dislike']['users'])) self.assertEqual(1, response.data['like']['count']) self.assertEqual(1, response.data['dislike']['count']) # Now we change the settings to keep anonymous the first [dis]like settings.VOTES_ID_LIMIT = anon_limit.pk # and we run the same tests # on first message we should see 1 like and 1 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[upvoted_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(1, len(response.data['like']['users'])) self.assertEqual(0, len(response.data['dislike']['users'])) self.assertEqual(2, response.data['like']['count']) self.assertEqual(0, response.data['dislike']['count']) # on second message we should see 1 dislikes and 1 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[downvoted_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(0, len(response.data['like']['users'])) self.assertEqual(1, len(response.data['dislike']['users'])) self.assertEqual(0, response.data['like']['count']) self.assertEqual(2, response.data['dislike']['count']) # on third message we should see 1 like and 1 dislike and 0 anonymous response = self.client.get(reverse('api:forum:post-karma', args=[equal_answer.pk])) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(1, len(response.data['like']['users'])) self.assertEqual(1, len(response.data['dislike']['users'])) self.assertEqual(1, response.data['like']['count']) self.assertEqual(1, response.data['dislike']['count'])
class LastPostFeedTest(TestCase): def setUp(self): # prepare a user and 2 Topic (with and without tags) settings.EMAIL_BACKEND = \ 'django.core.mail.backends.locmem.EmailBackend' self.category1 = CategoryFactory(position=1) self.forum = ForumFactory( category=self.category1, position_in_category=1) self.forum2 = ForumFactory( category=self.category1, position_in_category=2) self.forum3 = ForumFactory( category=self.category1, position_in_category=3) self.user = ProfileFactory().user log = self.client.login( username=self.user.username, password='******') self.assertEqual(log, True) self.tag = TagFactory() self.topic1 = TopicFactory(forum=self.forum, author=self.user) self.topic2 = TopicFactory(forum=self.forum2, author=self.user) self.topic2.tags.add(self.tag) self.topic2.save() # create 2 posts un each forum PostFactory(topic=self.topic1, author=self.user, position=1) PostFactory(topic=self.topic1, author=self.user, position=2) PostFactory(topic=self.topic2, author=self.user, position=1) PostFactory(topic=self.topic2, author=self.user, position=2) # and last topic + post alone self.tag2 = TagFactory() self.topic3 = TopicFactory(forum=self.forum3, author=self.user) self.post3 = PostFactory(topic=self.topic3, author=self.user, position=1) self.topic3.tags.add(self.tag2) self.topic3.save() self.postfeed = LastPostsFeedRSS() def test_is_well_setup(self): """ Test that base parameters are Ok """ self.assertEqual(self.postfeed.link, '/forums/') reftitle = 'Derniers messages sur {}'.format(settings.ZDS_APP['site']['literal_name']) self.assertEqual(self.postfeed.title, reftitle) refdescription = ('Les derniers messages ' 'parus sur le forum de {}.'.format(settings.ZDS_APP['site']['literal_name'])) self.assertEqual(self.postfeed.description, refdescription) atom = LastPostsFeedATOM() self.assertEqual(atom.subtitle, refdescription) def test_getobjects(self): """ Get object should return the given parameteres in an object """ factory = RequestFactory() request = factory.get(reverse('post-feed-rss') + '?forum=fofo&tag=tatag') obj = self.postfeed.get_object(request=request) self.assertEqual(obj['forum'], 'fofo') self.assertEqual(obj['tag'], 'tatag') def test_items_success(self): """ test that right items are sent back according to obj """ # test empty obj obj = {} # should return all topics topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 5) # test with a tag obj = {'tag': self.tag.pk} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 2) # test with a forum obj = {'forum': self.topic1.forum.pk} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 2) # test with a forum and a tag obj = {'forum': self.topic1.forum.pk, 'tag': self.tag.pk} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 0) def test_items_bad_cases(self): """ test that right items are sent back according to obj """ # test empty values, return value shoulb be empty obj = {'forum': -1, 'tag': -1} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 0) obj = {'forum': -1} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 0) obj = {'tag': -1} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 0) # with a weird object obj = {'forum': 'lol'} topics = self.postfeed.items(obj=obj) self.assertEqual(len(topics), 0) def test_get_pubdate(self): """ test the return value of pubdate """ ref = self.post3.pubdate posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_pubdate(item=posts[0]) self.assertEqual(ret.date(), ref.date()) def test_get_title(self): """ test the return value of title """ ref = '{}, message #{}'.format(self.post3.topic.title, self.post3.pk) posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_title(item=posts[0]) self.assertEqual(ret, ref) def test_get_description(self): """ test the return value of description """ ref = self.post3.text_html posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_description(item=posts[0]) self.assertEqual(ret, ref) def test_get_author_name(self): """ test the return value of author name """ ref = self.post3.author.username posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_author_name(item=posts[0]) self.assertEqual(ret, ref) def test_get_author_link(self): """ test the return value of author link """ ref = self.post3.author.get_absolute_url() posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_author_link(item=posts[0]) self.assertEqual(ret, ref) def test_get_item_link(self): """ test the return value of item link """ ref = self.post3.get_absolute_url() posts = self.postfeed.items(obj={'tag': self.tag2.pk}) ret = self.postfeed.item_link(item=posts[0]) self.assertEqual(ret, ref)
def test_es_manager(self): """Test the behavior of the ``es_manager`` command""" if not self.index_manager.connected_to_es: return # in the beginning: the void self.assertTrue(self.index_manager.index not in self.index_manager.es.cat.indices()) text = 'Ceci est un texte de test' # create a topic with a post topic = TopicFactory(forum=self.forum, author=self.user, title=text) post = PostFactory(topic=topic, author=self.user, position=1) post.text = post.text_html = text post.save() 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) chapter1.repo_update(text, text, text) extract1 = ExtractFactory(container=chapter1, db_object=tuto) version = extract1.repo_update(text, text) published = publish_content(tuto, tuto_draft, is_major_update=True) tuto.sha_public = version tuto.sha_draft = 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. test "index-all" call_command('es_manager', 'index_all') self.assertTrue(self.index_manager.es.indices.exists(self.index_manager.index)) self.index_manager.index_exists = True 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.index_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 "clear" self.assertTrue(self.index_manager.index in self.index_manager.es.cat.indices()) # index in call_command('es_manager', 'clear') self.assertFalse(self.index_manager.es.indices.exists(self.index_manager.index)) self.index_manager.index_exists = False # must reset every object 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) published = PublishedContent.objects.get(content_pk=tuto.pk) self.assertFalse(published.es_already_indexed) self.assertTrue(published.es_flagged) self.assertTrue(self.index_manager.index not in self.index_manager.es.cat.indices()) # index wiped out ! # 3. test "setup" call_command('es_manager', 'setup') self.assertTrue(self.index_manager.es.indices.exists(self.index_manager.index)) self.index_manager.index_exists = True self.assertTrue(self.index_manager.index in self.index_manager.es.cat.indices()) # index back in ... s = Search() s.query(MatchAll()) results = self.index_manager.setup_search(s).execute() self.assertEqual(len(results), 0) # ... but with nothing in it result = self.index_manager.es.indices.get_settings(index=self.index_manager.index) settings_index = result[self.index_manager.index]['settings']['index'] self.assertTrue('analysis' in settings_index) # custom analyzer was setup # 4. test "index-flagged" once ... call_command('es_manager', 'index_flagged') 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.index_manager.setup_search(s).execute() self.assertEqual(len(results), 4) # get the 4 results back
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_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_topic_impacts_posts(self): if not self.manager.connected_to_es: return # 1. Create a hidden forum belonging to a hidden group and add staff in it. text = 'test' group = Group.objects.create(name='Les illuminatis anonymes de ZdS') _, hidden_forum = create_category_and_forum(group) self.staff.groups.add(group) self.staff.save() # 2. Create a normal topic and index it 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() self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) 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=' + Post.get_es_document_type(), follow=False) self.assertEqual(result.status_code, 200) response = result.context['object_list'].execute() self.assertEqual(response.hits.total, 1) # ok self.assertEqual(response[0].meta.doc_type, Post.get_es_document_type()) self.assertEqual(response[0].forum_pk, self.forum.pk) self.assertEqual(response[0].topic_pk, topic_1.pk) self.assertEqual(response[0].topic_title, topic_1.title) # 3. Change topic title and reindex topic_1.title = 'new title' topic_1.save() self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) self.manager.refresh_index() 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, 1) # ok self.assertEqual(response[0].topic_title, topic_1.title) # title was changed # 4. connect with staff and move topic self.assertTrue(self.client.login(username=self.staff.username, password='******')) data = { 'move': '', 'forum': hidden_forum.pk, 'topic': topic_1.pk } response = self.client.post(reverse('topic-edit'), data, follow=False) self.assertEqual(302, response.status_code) self.manager.es_bulk_indexing_of_model(Topic) self.manager.es_bulk_indexing_of_model(Post) self.manager.refresh_index() 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, 1) # Note: without staff, would not get any results (see below) self.assertEqual(response[0].forum_pk, hidden_forum.pk) # post was updated with new forum # 5. Topic is now hidden self.client.logout() 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, 0) # ok
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