Example #1
0
    def test_merge_threads_kept_reads(self):
        """api keeps both threads readtrackers after merge"""
        self.override_acl({'can_merge_threads': 1})

        self.override_other_acl({'can_merge_threads': 1})

        other_thread = testutils.post_thread(self.category_b)

        poststracker.save_read(self.user, self.thread.first_post)
        poststracker.save_read(self.user, other_thread.first_post)

        response = self.client.post(
            self.api_link, {
                'other_thread': other_thread.get_absolute_url(),
            })
        self.assertContains(response,
                            other_thread.get_absolute_url(),
                            status_code=200)

        # posts reads are kept
        postreads = self.user.postread_set.filter(
            post__is_event=False).order_by('id')

        self.assertEqual(
            list(postreads.values_list('post_id', flat=True)),
            [self.thread.first_post_id, other_thread.first_post_id])
        self.assertEqual(postreads.filter(thread=other_thread).count(), 2)
        self.assertEqual(postreads.filter(category=self.category_b).count(), 2)
Example #2
0
    def test_move_thread_reads(self):
        """api moves thread reads together with thread"""
        self.override_acl({'can_move_threads': True})
        self.override_other_acl({'can_start_threads': 2})

        poststracker.save_read(self.user, self.thread.first_post)

        self.assertEqual(self.user.postread_set.count(), 1)
        self.user.postread_set.get(category=self.category)

        response = self.patch(self.api_link, [
            {
                'op': 'replace',
                'path': 'category',
                'value': self.category_b.pk,
            },
            {
                'op': 'add',
                'path': 'top-category',
                'value': self.category_b.pk,
            },
            {
                'op': 'replace',
                'path': 'flatten-categories',
                'value': None,
            },
        ])
        self.assertEqual(response.status_code, 200)

        # thread read was moved to new category
        postreads = self.user.postread_set.filter(
            post__is_event=False).order_by('id')

        self.assertEqual(postreads.count(), 1)
        postreads.get(category=self.category_b)
def record_event(request, thread, event_type, context=None, commit=True):
    time_now = timezone.now()

    event = Post.objects.create(
        category=thread.category,
        thread=thread,
        poster=request.user,
        poster_name=request.user.username,
        original='-',
        parsed='-',
        posted_on=time_now,
        updated_on=time_now,
        is_event=True,
        event_type=event_type,
        event_context=context,
    )

    thread.has_events = True
    thread.set_last_post(event)
    if commit:
        thread.save()

    if not (thread.is_hidden and thread.is_unapproved):
        thread.category.set_last_thread(thread)
        if commit:
            thread.category.save()

    poststracker.save_read(request.user, event)

    return event
Example #4
0
    def test_user_read_post(self):
        """tracked post is marked as read for authenticated users with read entry"""
        post = testutils.reply_thread(self.thread, posted_on=timezone.now())

        poststracker.save_read(self.user, post)
        poststracker.make_read_aware(self.user, post)

        self.assertTrue(post.is_read)
        self.assertFalse(post.is_new)
    def test_split_kitchensink(self):
        """api splits posts with kitchensink"""
        self.refresh_thread()
        self.assertEqual(self.thread.replies, 2)

        self.override_other_acl({
            'can_start_threads': 2,
            'can_close_threads': True,
            'can_hide_threads': True,
            'can_pin_threads': 2,
        })

        poststracker.save_read(self.user, self.thread.first_post)
        for post in self.posts:
            poststracker.save_read(self.user,
                                   Post.objects.select_related().get(pk=post))

        response = self.client.post(
            self.api_link,
            json.dumps({
                'posts': self.posts,
                'title': 'Split thread',
                'category': self.category_b.id,
                'weight': 2,
                'is_closed': 1,
                'is_hidden': 1,
            }),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)

        # thread was created
        split_thread = self.category_b.thread_set.get(slug='split-thread')
        self.assertEqual(split_thread.replies, 1)
        self.assertEqual(split_thread.weight, 2)
        self.assertTrue(split_thread.is_closed)
        self.assertTrue(split_thread.is_hidden)

        # posts were removed from old thread
        self.refresh_thread()
        self.assertEqual(self.thread.replies, 0)

        # posts were moved to new thread
        self.assertEqual(
            split_thread.post_set.filter(pk__in=self.posts).count(), 2)

        # postreads were removed
        postreads = self.user.postread_set.filter(
            post__is_event=False).order_by('id')

        postreads_threads = list(postreads.values_list('thread_id', flat=True))
        self.assertEqual(postreads_threads, [self.thread.pk])

        postreads_categories = list(
            postreads.values_list('category_id', flat=True))
        self.assertEqual(postreads_categories, [self.category.pk])
Example #6
0
    def test_user_read_post(self):
        """tracked thread with read post marked as read"""
        thread = testutils.post_thread(self.category,
                                       started_on=timezone.now())

        poststracker.save_read(self.user, thread.first_post)

        categoriestracker.make_read_aware(self.user, self.category)
        self.assertTrue(self.category.is_read)
        self.assertFalse(self.category.is_new)
Example #7
0
    def test_user_first_unread_last_read_post(self):
        """tracked thread with unread first and last read post marked as unread"""
        thread = testutils.post_thread(self.category,
                                       started_on=timezone.now())

        post = testutils.reply_thread(thread, posted_on=timezone.now())
        poststracker.save_read(self.user, post)

        categoriestracker.make_read_aware(self.user, self.category)
        self.assertFalse(self.category.is_read)
        self.assertTrue(self.category.is_new)
Example #8
0
    def test_user_first_read_post_unread_event(self):
        """tracked thread with read first post and unread event"""
        thread = testutils.post_thread(self.category,
                                       started_on=timezone.now())
        poststracker.save_read(self.user, thread.first_post)

        testutils.reply_thread(thread, posted_on=timezone.now(), is_event=True)

        categoriestracker.make_read_aware(self.user, self.category)
        self.assertFalse(self.category.is_read)
        self.assertTrue(self.category.is_new)
Example #9
0
    def test_goto_first_new_post(self):
        """first unread post redirect url in already read thread is valid"""
        save_read(self.user, self.thread.first_post)

        post = testutils.reply_thread(self.thread, posted_on=timezone.now())
        for _ in range(settings.MISAGO_POSTS_PER_PAGE +
                       settings.MISAGO_POSTS_TAIL - 1):
            testutils.reply_thread(self.thread, posted_on=timezone.now())

        response = self.client.get(self.thread.get_new_post_url())
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['location'],
                         GOTO_URL % (self.thread.get_absolute_url(), post.pk))
Example #10
0
    def test_delete_reads(self):
        """delete_reads util removes post's reads"""
        post = testutils.reply_thread(self.thread, posted_on=timezone.now())
        other_post = testutils.reply_thread(self.thread,
                                            posted_on=timezone.now())

        poststracker.save_read(self.user, post)
        poststracker.save_read(self.user, other_post)

        self.assertEqual(PostRead.objects.count(), 2)

        poststracker.delete_reads(post)

        self.assertEqual(PostRead.objects.count(), 1)
Example #11
0
    def test_goto_first_new_post_in_read_thread(self):
        """goto new in read thread points to last post"""
        save_read(self.user, self.thread.first_post)

        for _ in range(settings.MISAGO_POSTS_PER_PAGE +
                       settings.MISAGO_POSTS_TAIL):
            post = testutils.reply_thread(self.thread,
                                          posted_on=timezone.now())
            save_read(self.user, post)

        response = self.client.get(self.thread.get_new_post_url())
        self.assertEqual(response.status_code, 302)
        self.assertEqual(
            response['location'],
            GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk))
def post_read_endpoint(request, thread, post):
    poststracker.make_read_aware(request.user, post)
    if post.is_new:
        poststracker.save_read(request.user, post)
        if thread.subscription and thread.subscription.last_read_on < post.posted_on:
            thread.subscription.last_read_on = post.posted_on
            thread.subscription.save()

    threadstracker.make_read_aware(request.user, thread)

    # send signal if post read marked thread as read
    # used in some places, eg. syncing unread thread count
    if post.is_new and thread.is_read:
        thread_read.send(request.user, thread=thread)

    return Response({'thread_is_read': thread.is_read})
    def test_merge_remove_reads(self):
        """two posts merge removes read tracker from post"""
        post_a = testutils.reply_thread(self.thread, poster=self.user, message="Battęry")
        post_b = testutils.reply_thread(self.thread, poster=self.user, message="Hórse")

        poststracker.save_read(self.user, post_a)
        poststracker.save_read(self.user, post_b)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'posts': [post_a.pk, post_b.pk]
            }),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)

        # both post's were removed from readtracker
        self.assertEqual(self.user.postread_set.count(), 0)
    def test_move_posts_reads(self):
        """api moves posts reads together with posts"""
        self.override_other_acl({'can_reply_threads': 1})

        other_thread = testutils.post_thread(self.category_b)

        posts = (
            testutils.reply_thread(self.thread),
            testutils.reply_thread(self.thread),
        )

        self.refresh_thread()
        self.assertEqual(self.thread.replies, 2)

        poststracker.save_read(self.user, self.thread.first_post)
        for post in posts:
            poststracker.save_read(self.user, post)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
                'posts': [p.pk for p in posts],
            }),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)

        other_thread = Thread.objects.get(pk=other_thread.pk)

        # postreads were removed
        postreads = self.user.postread_set.order_by('id')

        postreads_threads = list(postreads.values_list('thread_id', flat=True))
        self.assertEqual(postreads_threads, [self.thread.pk])

        postreads_categories = list(
            postreads.values_list('category_id', flat=True))
        self.assertEqual(postreads_categories, [self.category.pk])
Example #15
0
    def test_merge_kitchensink(self):
        """api performs merge"""
        posts_ids = [p.id for p in Post.objects.all()]

        self.override_acl({
            'can_merge_threads': True,
            'can_close_threads': True,
            'can_hide_threads': 1,
            'can_pin_threads': 2,
        })

        thread = testutils.post_thread(category=self.category)

        poststracker.save_read(self.user, self.thread.first_post)
        poststracker.save_read(self.user, thread.first_post)

        self.user.subscription_set.create(
            thread=self.thread,
            category=self.thread.category,
            last_read_on=self.thread.last_post_on,
            send_email=False,
        )
        self.user.subscription_set.create(
            thread=thread,
            category=thread.category,
            last_read_on=thread.last_post_on,
            send_email=False,
        )

        response = self.client.post(
            self.api_link,
            json.dumps({
                'threads': [self.thread.id, thread.id],
                'title': 'Merged thread!',
                'category': self.category.id,
                'is_closed': 1,
                'is_hidden': 1,
                'weight': 2,
            }),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)

        # is response json with new thread?
        response_json = response.json()

        new_thread = Thread.objects.get(pk=response_json['id'])
        new_thread.is_read = False
        new_thread.subscription = None

        self.assertEqual(new_thread.weight, 2)
        self.assertTrue(new_thread.is_closed)
        self.assertTrue(new_thread.is_hidden)

        add_acl(self.user, new_thread.category)
        add_acl(self.user, new_thread)

        self.assertEqual(response_json, ThreadsListSerializer(new_thread).data)

        # did posts move to new thread?
        for post in Post.objects.filter(id__in=posts_ids):
            self.assertEqual(post.thread_id, new_thread.id)

        # are old threads gone?
        self.assertEqual([t.pk for t in Thread.objects.all()], [new_thread.pk])

        # posts reads are kept
        postreads = self.user.postread_set.filter(
            post__is_event=False).order_by('id')

        self.assertEqual(list(postreads.values_list('post_id', flat=True)),
                         [self.thread.first_post_id, thread.first_post_id])
        self.assertEqual(postreads.filter(thread=new_thread).count(), 2)
        self.assertEqual(postreads.filter(category=self.category).count(), 2)

        # subscriptions are kept
        self.assertEqual(self.user.subscription_set.count(), 1)
        self.user.subscription_set.get(thread=new_thread)
        self.user.subscription_set.get(category=self.category)