def test_delete_category_and_contents(self):
        """category and its contents were deleted"""
        for _ in range(10):
            testutils.post_thread(self.category_b)

        response = self.client.get(
            reverse('misago:admin:categories:nodes:delete', kwargs={
                'pk': self.category_b.pk,
            })
        )
        self.assertEqual(response.status_code, 200)

        response = self.client.post(
            reverse('misago:admin:categories:nodes:delete', kwargs={
                'pk': self.category_b.pk,
            }),
            data={
                'move_children_to': '',
                'move_threads_to': '',
            }
        )
        self.assertEqual(response.status_code, 302)

        self.assertEqual(Category.objects.all_categories().count(), 4)
        self.assertEqual(Thread.objects.count(), 0)

        self.assertValidTree([
            (self.root, 0, 1, 10),
            (self.first_category, 1, 2, 3),
            (self.category_a, 1, 4, 5),
            (self.category_e, 1, 6, 9),
            (self.category_f, 2, 7, 8),
        ])
    def test_moderated_threads_visibility(self):
        """moderated threads are not rendered to non-moderator, except owned"""
        test_acl = {
            'can_see': 1,
            'can_browse': 1,
            'can_see_all_threads': 1,
            'can_review_moderated_content': 0,
        }

        test_title = "Test moderated thread"
        thread = testutils.post_thread(
            forum=self.forum, title=test_title, is_moderated=True)

        self.override_acl(test_acl)
        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertNotIn(test_title, response.content)

        test_title = "Test owned moderated thread"
        thread = testutils.post_thread(
            forum=self.forum,
            title=test_title,
            is_moderated=True,
            poster=self.user)

        self.override_acl(test_acl)
        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn(test_title, response.content)
Exemple #3
0
    def test_category_prune_by_last_reply(self):
        """command prunes category content based on last reply date"""
        category = Category.objects.all_categories()[:1][0]

        category.prune_replied_after = 20
        category.save()

        # post old threads with recent replies
        started_on = timezone.now() - timedelta(days=30)
        for t in range(10):
            thread = testutils.post_thread(category, started_on=started_on)
            testutils.reply_thread(thread)

        # post recent threads that will be preserved
        threads = [testutils.post_thread(category) for t in range(10)]

        category.synchronize()
        self.assertEqual(category.threads, 20)
        self.assertEqual(category.posts, 30)

        # run command
        command = prunecategories.Command()

        out = StringIO()
        command.execute(stdout=out)

        category.synchronize()
        self.assertEqual(category.threads, 10)
        self.assertEqual(category.posts, 10)

        for thread in threads:
            category.thread_set.get(id=thread.id)

        command_output = out.getvalue().strip()
        self.assertEqual(command_output, 'Categories were pruned')
    def test_thread_visibility(self):
        """only participated threads are returned by private threads api"""
        visible = testutils.post_thread(category=self.category, poster=self.user)
        reported = testutils.post_thread(category=self.category, poster=self.user)

        # hidden thread
        testutils.post_thread(category=self.category, poster=self.user)

        ThreadParticipant.objects.add_participants(visible, [self.user])

        reported.has_reported_posts = True
        reported.save()

        response = self.client.get(self.api_link)
        self.assertEqual(response.status_code, 200)

        response_json = response.json()
        self.assertEqual(response_json['count'], 1)
        self.assertEqual(response_json['results'][0]['id'], visible.id)

        # threads with reported posts will also show to moderators
        override_acl(self.user, {'can_moderate_private_threads': 1})

        response = self.client.get(self.api_link)
        self.assertEqual(response.status_code, 200)

        response_json = response.json()
        self.assertEqual(response_json['count'], 2)
        self.assertEqual(response_json['results'][0]['id'], reported.id)
        self.assertEqual(response_json['results'][1]['id'], visible.id)
    def test_forum_prune_by_last_reply(self):
        """command prunes forum content based on last reply date"""
        forum = Forum.objects.all_forums().filter(role="forum")[:1][0]

        forum.prune_replied_after = 20
        forum.save()

        # post old threads with recent replies
        started_on = timezone.now() - timedelta(days=30)
        for t in xrange(10):
            thread = testutils.post_thread(forum, started_on=started_on)
            testutils.reply_thread(thread)

        # post recent threads that will be preserved
        threads = [testutils.post_thread(forum) for t in xrange(10)]

        forum.synchronize()
        self.assertEqual(forum.threads, 20)
        self.assertEqual(forum.posts, 30)

        # run command
        command = pruneforums.Command()

        out = StringIO()
        command.execute(stdout=out)

        forum.synchronize()
        self.assertEqual(forum.threads, 10)
        self.assertEqual(forum.posts, 10)

        for thread in threads:
            forum.thread_set.get(id=thread.id)

        command_output = out.getvalue().strip()
        self.assertEqual(command_output, 'Forums were pruned')
    def test_anonymous_request(self):
        """view renders to anonymous users"""
        anon_title = "Hello Anon!"
        testutils.post_thread(forum=self.forum, title=anon_title)

        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn(anon_title, response.content)
    def test_user_with_no_threads(self):
        """user with no private threads has 0 unread threads"""
        for i in range(5):
            # post 5 invisible threads
            testutils.post_thread(
                self.forum, started_on=timezone.now() - timedelta(days=2))

        sync_user_unread_private_threads_count(self.user)
        self.assertEqual(self.user.unread_private_threads, 0)
    def setUp(self):
        super(ThreadsBulkPatchApiTestCase, self).setUp()

        self.threads = list(reversed([
            testutils.post_thread(category=self.category),
            testutils.post_thread(category=self.category),
            testutils.post_thread(category=self.category),
        ]))

        self.ids = list(reversed([t.id for t in self.threads]))

        self.api_link = reverse('misago:api:thread-list')
    def test_list_with_threads(self):
        """list returns list of visible threads"""
        test_threads = [
            testutils.post_thread(
                forum=self.forum,
                title="Hello, I am thread",
                is_moderated=False,
                poster=self.user),
            testutils.post_thread(
                forum=self.forum,
                title="Hello, I am moderated thread",
                is_moderated=True,
                poster=self.user),
            testutils.post_thread(
                forum=self.forum,
                title="Hello, I am other user thread",
                is_moderated=False,
                poster="Bob"),
            testutils.post_thread(
                forum=self.forum,
                title="Hello, I am other user moderated thread",
                is_moderated=True,
                poster="Bob"),
        ]

        self.override_acl({
            'can_see_all_threads': False,
            'can_review_moderated_content': False
        })

        threads = ForumThreads(self.user, self.forum)
        self.assertEqual(threads.list(), [test_threads[1], test_threads[0]])

        self.override_acl({
            'can_see_all_threads': True,
            'can_review_moderated_content': False
        })

        threads = ForumThreads(self.user, self.forum)
        self.assertEqual(threads.list(),
                         [test_threads[2], test_threads[1], test_threads[0]])

        self.override_acl({
            'can_see_all_threads': True,
            'can_review_moderated_content': True
        })

        threads = ForumThreads(self.user, self.forum)
        test_threads.reverse()
        self.assertEqual(threads.list(), test_threads)

        self.assertTrue(threads.page)
        self.assertTrue(threads.paginator)
    def test_delete_threads(self):
        """moderation allows for deleting threads"""
        threads = [testutils.post_thread(self.forum) for t in xrange(10)]

        self.forum.synchronize()
        self.assertEqual(self.forum.threads, 10)

        test_acl = {
            'can_see': 1,
            'can_browse': 1,
            'can_see_all_threads': 1,
            'can_hide_threads': 2
        }

        self.override_acl(test_acl)
        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn("Delete threads", response.content)

        self.override_acl(test_acl)
        response = self.client.post(self.link, data={
            'action': 'delete', 'item': [t.pk for t in threads]
        })
        self.assertEqual(response.status_code, 302)
        self.assertTrue(response['location'].endswith(self.link))

        forum = Forum.objects.get(pk=self.forum.pk)
        self.assertEqual(forum.threads, 0)

        threads = [testutils.post_thread(self.forum) for t in xrange(60)]

        second_page_link = reverse('misago:forum', kwargs={
            'forum_id': self.forum.id,
            'forum_slug': self.forum.slug,
            'page': 2
        })

        self.override_acl(test_acl)
        response = self.client.post(second_page_link, data={
            'action': 'delete', 'item': [t.pk for t in threads[20:40]]
        })
        self.assertEqual(response.status_code, 302)
        self.assertTrue(response['location'].endswith(second_page_link))

        forum = Forum.objects.get(pk=self.forum.pk)
        self.assertEqual(forum.threads, 40)

        self.override_acl(test_acl)
        response = self.client.post(second_page_link, data={
            'action': 'delete', 'item': [t.pk for t in threads[:-20]]
        })
        self.assertEqual(response.status_code, 302)
        self.assertTrue(response['location'].endswith(self.link))
Exemple #11
0
    def test_user_with_new_thread(self):
        """user has one new private thread"""
        for i in range(5):
            # post 5 invisible threads
            testutils.post_thread(
                self.forum, started_on=timezone.now() - timedelta(days=2))

        thread = testutils.post_thread(
            self.forum, started_on=timezone.now() - timedelta(days=2))
        thread.threadparticipant_set.create(user=self.user)

        sync_user_unread_private_threads_count(self.user)
        self.assertEqual(self.user.unread_private_threads, 1)
Exemple #12
0
    def test_category_archive_by_start_date(self):
        """command archives category content based on start date"""
        category = Category.objects.all_categories()[:1][0]
        archive = Category.objects.create(
            lft=7,
            rght=8,
            tree_id=2,
            level=0,
            name='Archive',
            slug='archive',
        )

        category.prune_started_after = 20
        category.archive_pruned_in = archive
        category.save()

        # post old threads with recent replies
        started_on = timezone.now() - timedelta(days=30)
        posted_on = timezone.now()
        for t in range(10):
            thread = testutils.post_thread(category, started_on=started_on)
            testutils.reply_thread(thread, posted_on=posted_on)

        # post recent threads that will be preserved
        threads = [testutils.post_thread(category) for t in range(10)]

        category.synchronize()
        self.assertEqual(category.threads, 20)
        self.assertEqual(category.posts, 30)

        # run command
        command = prunecategories.Command()

        out = StringIO()
        command.execute(stdout=out)

        category.synchronize()
        self.assertEqual(category.threads, 10)
        self.assertEqual(category.posts, 10)

        archive.synchronize()
        self.assertEqual(archive.threads, 10)
        self.assertEqual(archive.posts, 20)

        for thread in threads:
            category.thread_set.get(id=thread.id)

        command_output = out.getvalue().strip()
        self.assertEqual(command_output, 'Categories were pruned')
Exemple #13
0
    def test_filled_list(self):
        """filled list is served"""
        post_thread(self.forum, poster=self.user)
        self.user.posts = 1
        self.user.save()

        self.logout_user()

        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn(self.user.username, response.content)

        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn(self.user.username, response.content)
    def test_filtered_query(self):
        """search filters are used by search system"""
        thread = testutils.post_thread(self.category)
        post = testutils.reply_thread(
            thread,
            message="You just do MMM in 4th minute and its pwnt",
        )

        self.index_post(post)

        response = self.client.get('%s?q=MMM' % self.api_link)
        self.assertEqual(response.status_code, 200)

        reponse_json = response.json()
        self.assertIn('threads', [p['id'] for p in reponse_json])

        for provider in reponse_json:
            if provider['id'] == 'threads':
                results = provider['results']['results']
                self.assertEqual(len(results), 1)
                self.assertEqual(results[0]['id'], post.id)

        response = self.client.get('%s?q=Marines Medics' % self.api_link)
        self.assertEqual(response.status_code, 200)

        for provider in reponse_json:
            if provider['id'] == 'threads':
                results = provider['results']['results']
                self.assertEqual(len(results), 1)
                self.assertEqual(results[0]['id'], post.id)
Exemple #15
0
    def test_direct_child_thread_from_parent(self):
        """thread in direct child category is handled"""
        thread = testutils.post_thread(category=self.category_e)
        add_categories_to_threads(self.root, self.categories, [thread])

        self.assertEqual(thread.top_category, self.category_e)
        self.assertEqual(thread.category, self.category_e)
    def setUp(self):
        super(PrivateThreadDeleteApiTests, self).setUp()

        self.thread = testutils.post_thread(self.category, poster=self.user)
        self.api_link = self.thread.get_api_url()

        ThreadParticipant.objects.add_participants(self.thread, [self.user])
Exemple #17
0
    def create_thread(self):
        datetime = timezone.now()

        thread = testutils.post_thread(self.forum)
        post = testutils.reply_thread(thread)

        return thread
    def test_threads_not_found(self):
        """api fails to find threads"""
        threads = [
            testutils.post_thread(category=self.category, is_hidden=True),
            testutils.post_thread(category=self.category, is_unapproved=True),
        ]

        response = self.patch(self.api_link, {
            'ids': [t.id for t in threads],
            'ops': [{}],
        })

        self.assertEqual(response.status_code, 403)
        self.assertEqual(response.json(), {
            'detail': "One or more threads to update could not be found.",
        })
Exemple #19
0
    def setUp(self):
        super(ThreadApiTestCase, self).setUp()

        self.category = Category.objects.get(slug='first-category')

        self.thread = testutils.post_thread(category=self.category)
        self.api_link = self.thread.get_api_url()
    def test_merge_threads_moved_poll(self):
        """api merges two threads successfully, moving poll from other thread"""
        self.override_acl({'can_merge_threads': 1})

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

        other_thread = testutils.post_thread(self.category_b)
        poll = testutils.post_poll(self.thread, self.user)

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

        # other thread has two posts now
        self.assertEqual(other_thread.post_set.count(), 3)

        # first thread is gone
        with self.assertRaises(Thread.DoesNotExist):
            Thread.objects.get(pk=self.thread.pk)

        # poll and its votes were moved
        self.assertEqual(Poll.objects.filter(pk=poll.pk, thread=other_thread).count(), 1)
        self.assertEqual(PollVote.objects.filter(poll=poll, thread=other_thread).count(), 4)
    def test_filled_threads_list(self):
        """filled threads list is rendered"""
        forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
        threads = [testutils.post_thread(forum) for t in xrange(10)]

        # only unread tracker threads are shown on unread list
        response = self.client.get(reverse('misago:unread_threads'))
        self.assertEqual(response.status_code, 200)
        self.assertIn("There are no threads with unread", response.content)

        # we'll read and reply to first five threads
        for thread in threads[5:]:
            response = self.client.get(thread.get_absolute_url())
            testutils.reply_thread(thread, posted_on=timezone.now())

        # assert that replied threads show on list
        response = self.client.get(reverse('misago:unread_threads'))
        self.assertEqual(response.status_code, 200)
        for thread in threads[5:]:
            self.assertIn(thread.get_absolute_url(), response.content)
        for thread in threads[:5]:
            self.assertNotIn(thread.get_absolute_url(), response.content)

        # clear list
        response = self.client.post(reverse('misago:clear_unread_threads'))
        self.assertEqual(response.status_code, 302)

        response = self.client.get(response['location'])
        self.assertEqual(response.status_code, 200)
        self.assertIn("There are no threads with unread", response.content)
    def setUp(self):
        super(GotoListsViewsTests, self).setUp()

        self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
        self.forum.labels = []

        self.thread = post_thread(self.forum)
    def test_threads_merge_conflict(self):
        """api errors on merge conflict, returning list of available polls"""
        self.override_acl({'can_merge_threads': 1})

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

        other_thread = testutils.post_thread(self.category_b)
        poll = testutils.post_poll(self.thread, self.user)
        other_poll = testutils.post_poll(other_thread, self.user)

        response = self.client.post(
            self.api_link, {
                'thread_url': other_thread.get_absolute_url(),
            }
        )
        self.assertEqual(response.status_code, 400)
        self.assertEqual(
            response.json(), {
                'polls': [
                    [0, "Delete all polls"],
                    [poll.pk, poll.question],
                    [other_poll.pk, other_poll.question],
                ]
            }
        )

        # polls and votes were untouched
        self.assertEqual(Poll.objects.count(), 2)
        self.assertEqual(PollVote.objects.count(), 8)
    def test_threads_merge_conflict_delete_all(self):
        """api deletes all polls when delete all choice is selected"""
        self.override_acl({'can_merge_threads': 1})

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

        other_thread = testutils.post_thread(self.category_b)
        testutils.post_poll(self.thread, self.user)
        testutils.post_poll(other_thread, self.user)

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

        # other thread has two posts now
        self.assertEqual(other_thread.post_set.count(), 3)

        # first thread is gone
        with self.assertRaises(Thread.DoesNotExist):
            Thread.objects.get(pk=self.thread.pk)

        # polls and votes are gone
        self.assertEqual(Poll.objects.count(), 0)
        self.assertEqual(PollVote.objects.count(), 0)
    def test_single_page_threads_list(self):
        """filled threads list is rendered"""
        forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
        threads = [testutils.post_thread(forum) for t in xrange(10)]

        response = self.client.get(reverse('misago:new_threads'))
        self.assertEqual(response.status_code, 200)
        for thread in threads:
            self.assertIn(thread.get_absolute_url(), response.content)

        # read half of threads
        for thread in threads[5:]:
            response = self.client.get(thread.get_absolute_url())

        # assert first half is no longer shown on list
        response = self.client.get(reverse('misago:new_threads'))
        for thread in threads[5:]:
            self.assertNotIn(thread.get_absolute_url(), response.content)
        for thread in threads[:5]:
            self.assertIn(thread.get_absolute_url(), response.content)

        # clear list
        response = self.client.post(reverse('misago:clear_new_threads'))
        self.assertEqual(response.status_code, 302)

        response = self.client.get(response['location'])
        self.assertEqual(response.status_code, 200)
        self.assertIn("There are no threads from last", response.content)
    def test_threads_merge_conflict_keep_other_poll(self):
        """api deletes first poll on merge"""
        self.override_acl({'can_merge_threads': 1})

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

        other_thread = testutils.post_thread(self.category_b)
        poll = testutils.post_poll(self.thread, self.user)
        other_poll = testutils.post_poll(other_thread, self.user)

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

        # other thread has two posts now
        self.assertEqual(other_thread.post_set.count(), 3)

        # first thread is gone
        with self.assertRaises(Thread.DoesNotExist):
            Thread.objects.get(pk=self.thread.pk)

        # other poll and its votes are gone
        self.assertEqual(Poll.objects.filter(thread=self.thread).count(), 0)
        self.assertEqual(PollVote.objects.filter(thread=self.thread).count(), 0)

        self.assertEqual(Poll.objects.filter(thread=other_thread).count(), 1)
        self.assertEqual(PollVote.objects.filter(thread=other_thread).count(), 4)

        Poll.objects.get(pk=other_poll.pk)
        with self.assertRaises(Poll.DoesNotExist):
            Poll.objects.get(pk=poll.pk)
Exemple #27
0
    def setUp(self):
        super(ThreadViewTestCase, self).setUp()

        self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
        self.forum.labels = []

        self.thread = post_thread(self.forum)
    def test_delete_threads(self):
        """moderation allows for deleting threads"""
        threads = [testutils.post_thread(self.forum) for t in xrange(10)]

        self.forum.synchronize()
        self.assertEqual(self.forum.threads, 10)

        test_acl = {
            'can_see': 1,
            'can_browse': 1,
            'can_see_all_threads': 1,
            'can_hide_threads': 2
        }

        self.override_acl(test_acl)
        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertIn("Delete threads", response.content)

        self.override_acl(test_acl)
        response = self.client.post(self.link, data={
            'action': 'delete', 'thread': [t.pk for t in threads]
        })

        forum = Forum.objects.get(pk=self.forum.pk)
        self.assertEqual(forum.threads, 0)
    def test_delete_expired_thread(self):
        """test deletes one expired thread tracker, but spares the other"""
        thread = testutils.post_thread(self.category)

        existing = ThreadRead.objects.create(
            user=self.user_a,
            category=self.category,
            thread=thread,
            last_read_on=timezone.now() - timedelta(days=settings.MISAGO_READTRACKER_CUTOFF / 4)
        )

        deleted = ThreadRead.objects.create(
            user=self.user_b,
            category=self.category,
            thread=thread,
            last_read_on=timezone.now() - timedelta(days=settings.MISAGO_READTRACKER_CUTOFF * 2)
        )

        command = clearreadtracker.Command()

        out = StringIO()
        call_command(command, stdout=out)
        command_output = out.getvalue().strip()

        self.assertEqual(command_output, "Deleted 1 expired entries")

        ThreadRead.objects.get(pk=existing.pk)
        with self.assertRaises(ThreadRead.DoesNotExist):
            ThreadRead.objects.get(pk=deleted.pk)
    def test_thread_is_closed(self):
        """api validates if thread is open"""
        self.override_acl({'can_merge_threads': 1})

        self.override_other_acl({
            'can_merge_threads': 1,
            'can_reply_threads': 0,
            'can_close_threads': 0,
        })

        other_thread = testutils.post_thread(self.category_b)

        self.thread.is_closed = True
        self.thread.save()

        response = self.client.post(
            self.api_link, {
                'thread_url': other_thread.get_absolute_url(),
            }
        )
        self.assertContains(
            response,
            "This thread is closed. You can't merge it with other threads.",
            status_code=403,
        )
Exemple #31
0
    def test_filled_list(self):
        """filled list is served"""
        post_thread(self.category, poster=self.user)
        self.user.posts = 1
        self.user.save()

        build_active_posters_ranking()

        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, self.user.username)
        self.assertContains(response, '"is_online":true')
        self.assertContains(response, '"is_offline":false')

        self.logout_user()
        build_active_posters_ranking()

        response = self.client.get(self.link)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, self.user.username)
        self.assertContains(response, '"is_online":false')
        self.assertContains(response, '"is_offline":true')
    def test_delete_category_move_contents(self):
        """category was deleted and its contents were moved"""
        for _ in range(10):
            testutils.post_thread(self.category_b)
        self.assertEqual(Thread.objects.count(), 10)

        response = self.client.get(
            reverse('misago:admin:categories:nodes:delete',
                    kwargs={
                        'pk': self.category_b.pk,
                    }))
        self.assertEqual(response.status_code, 200)

        response = self.client.post(
            reverse('misago:admin:categories:nodes:delete',
                    kwargs={
                        'pk': self.category_b.pk,
                    }),
            data={
                'move_children_to': self.category_e.pk,
                'move_threads_to': self.category_d.pk,
            },
        )
        self.assertEqual(response.status_code, 302)
        self.assertEqual(Category.objects.all_categories().count(), 6)
        self.assertEqual(Thread.objects.count(), 10)
        for thread in Thread.objects.all():
            self.assertEqual(thread.category_id, self.category_d.pk)

        self.assertValidTree([
            (self.root, 0, 1, 14),
            (self.first_category, 1, 2, 3),
            (self.category_a, 1, 4, 5),
            (self.category_e, 1, 6, 13),
            (self.category_f, 2, 7, 8),
            (self.category_c, 2, 9, 10),
            (self.category_d, 2, 11, 12),
        ])
Exemple #33
0
    def test_get_current_count_dict(self):
        """get_current_count_dict returns valid count of new threads"""
        counter = NewThreadsCount(self.user, {})
        self.assertEqual(counter.count, 0)
        self.assertEqual(counter.get_current_count_dict()['threads'], 0)

        # create 10 new threads
        threads = [testutils.post_thread(self.forum) for t in xrange(10)]
        self.assertEqual(counter.get_current_count_dict()['threads'], 10)

        # create new counter
        counter = NewThreadsCount(self.user, {})
        self.assertEqual(counter.count, 10)
        self.assertEqual(counter.get_current_count_dict()['threads'], 10)
    def test_merge_cross_threads(self):
        """api recjects attempt to merge with post made in other thread"""
        other_thread = testutils.post_thread(category=self.category)
        other_post = testutils.reply_thread(other_thread, poster=self.user)

        response = self.client.post(
            self.api_link,
            json.dumps({'posts': [self.post.pk, other_post.pk]}),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.json(), {
            'posts': ["One or more posts to merge could not be found."],
        })
Exemple #35
0
    def test_move_first_post(self):
        """api rejects first post move"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(self.api_link,
                                    json.dumps({
                                        'thread_url':
                                        other_thread.get_absolute_url(),
                                        'posts': [self.thread.first_post_id]
                                    }),
                                    content_type="application/json")
        self.assertContains(response,
                            "You can't move thread's first post.",
                            status_code=400)
Exemple #36
0
    def test_no_posts_ids(self):
        """api rejects no posts ids"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(self.api_link,
                                    json.dumps({
                                        'thread_url':
                                        other_thread.get_absolute_url(),
                                        'posts': []
                                    }),
                                    content_type="application/json")
        self.assertContains(response,
                            "You have to specify at least one post to move.",
                            status_code=400)
Exemple #37
0
    def test_user_thread_anonymous(self):
        """user thread shows in feed requested by unauthenticated user"""
        thread = testutils.post_thread(
            category=self.category,
            poster=self.user,
        )

        self.logout_user()

        response = self.client.get(self.api_link)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()['count'], 1)
        self.assertEqual(response.json()['results'][0]['id'],
                         thread.first_post_id)
    def test_other_thread_is_invisible(self):
        """api validates if other thread is visible"""
        self.override_other_acl({'can_see': 0})

        other_thread = testutils.post_thread(self.category_b)

        response = self.client.post(
            self.api_link, {
                'new_thread': other_thread.get_absolute_url(),
            }
        )
        self.assertContains(
            response, "The thread you have entered link to doesn't exist", status_code=400
        )
    def setUp(self):
        super(EmailNotificationTests, self).setUp()

        self.category = Category.objects.get(slug='first-category')
        self.thread = testutils.post_thread(category=self.category,
                                            started_on=timezone.now() -
                                            timedelta(seconds=5))
        self.override_acl()

        self.api_link = reverse('misago:api:thread-post-list',
                                kwargs={'thread_pk': self.thread.pk})

        self.other_user = UserModel.objects.create_user(
            'Bob', '*****@*****.**', 'pass123')
    def test_empty_posts_data_form(self):
        """api handles empty form data"""
        other_thread = testutils.post_thread(self.category)

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

        self.assertContains(
            response, "You have to specify at least one post to move.", status_code=400
        )
    def test_merge_with_invisible_thread(self):
        """api validates if we are trying to merge with inaccesible thread"""
        unaccesible_thread = testutils.post_thread(category=self.category_b)

        response = self.client.post(
            self.api_link,
            json.dumps({'threads': [self.thread.id, unaccesible_thread.id]}),
            content_type="application/json")
        self.assertEqual(response.status_code, 403)

        response_json = json.loads(response.content)
        self.assertEqual(
            response_json,
            {'detail': "One or more threads to merge could not be found."})
Exemple #42
0
    def test_thread_merged_event_renders(self):
        """merged thread event renders"""
        other_thread = testutils.post_thread(category=self.category)
        threads_moderation.merge_thread(MockRequest(self.user), self.thread,
                                        other_thread)

        event = self.thread.post_set.filter(is_event=True)[0]
        self.assertEqual(event.event_type, 'merged')

        # event renders
        response = self.client.get(self.thread.get_absolute_url())
        self.assertContains(response, event.get_absolute_url())
        self.assertContains(response,
                            "thread has been merged into this thread")
Exemple #43
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)

        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
        new_thread.top_category = 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])
    def test_other_thread_isnt_replyable(self):
        """api validates if other thread can be replied"""
        self.override_other_acl({'can_reply_threads': 0})

        other_thread = testutils.post_thread(self.category_b)

        response = self.client.post(
            self.api_link, {
                'new_thread': other_thread.get_absolute_url(),
            }
        )
        self.assertContains(
            response, "You can't move posts to threads you can't reply.", status_code=400
        )
Exemple #45
0
    def test_invalid_posts_ids(self):
        """api handles invalid post id"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(self.api_link,
                                    json.dumps({
                                        'thread_url':
                                        other_thread.get_absolute_url(),
                                        'posts': [1, 2, 'string']
                                    }),
                                    content_type="application/json")
        self.assertContains(response,
                            "One or more post ids received were invalid.",
                            status_code=400)
    def test_other_thread_exists(self):
        """api validates if other thread exists"""
        self.override_other_acl()

        other_thread = testutils.post_thread(self.category_b)
        other_new_thread = other_thread.get_absolute_url()
        other_thread.delete()

        response = self.client.post(self.api_link, {
            'new_thread': other_new_thread,
        })
        self.assertContains(
            response, "The thread you have entered link to doesn't exist", status_code=400
        )
    def test_split_other_thread_posts(self):
        """api recjects attempt to split other thread's post"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'posts': [testutils.reply_thread(other_thread, is_hidden=True).pk],
            }),
            content_type="application/json",
        )
        self.assertContains(
            response, "One or more posts to split could not be found.", status_code=400
        )
    def setUp(self):
        super(ThreadPostPatchApiTestCase, self).setUp()

        self.category = Category.objects.get(slug='first-category')
        self.thread = testutils.post_thread(category=self.category)
        self.post = testutils.reply_thread(self.thread, poster=self.user)

        self.api_link = reverse(
            'misago:api:thread-post-detail',
            kwargs={
                'thread_pk': self.thread.pk,
                'pk': self.post.pk,
            }
        )
Exemple #49
0
    def test_user_thread(self):
        """user thread shows in feed"""
        thread = testutils.post_thread(
            category=self.category,
            poster=self.user,
        )
        post = testutils.reply_thread(thread, poster=self.user)

        response = self.client.get(self.api_link)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()['count'], 2)
        self.assertEqual(response.json()['results'][0]['id'], post.pk)
        self.assertEqual(response.json()['results'][1]['id'],
                         thread.first_post_id)
    def test_delete_leaf_category_and_contents(self):
        """leaf category was deleted with contents"""
        for _ in range(10):
            testutils.post_thread(self.category_d)
        self.assertEqual(Thread.objects.count(), 10)

        response = self.client.get(
            reverse('misago:admin:categories:nodes:delete',
                    kwargs={
                        'pk': self.category_d.pk,
                    }))
        self.assertEqual(response.status_code, 200)

        response = self.client.post(reverse(
            'misago:admin:categories:nodes:delete',
            kwargs={
                'pk': self.category_d.pk,
            }),
                                    data={
                                        'move_children_to': '',
                                        'move_threads_to': '',
                                    })
        self.assertEqual(response.status_code, 302)

        self.assertEqual(Category.objects.all_categories().count(), 6)
        self.assertEqual(Thread.objects.count(), 0)

        self.assertValidTree([
            (self.root, 0, 1, 14),
            (self.first_category, 1, 2, 3),
            (self.category_a, 1, 4, 9),
            (self.category_b, 2, 5, 8),
            (self.category_c, 3, 6, 7),
            (self.category_e, 1, 10, 13),
            (self.category_f, 2, 11, 12),
        ])
Exemple #51
0
    def test_forum_prune_by_start_date(self):
        """command prunes forum content based on start date"""
        forum = Forum.objects.all_forums().filter(role="forum")[:1][0]

        forum.prune_started_after = 20
        forum.save()

        # post old threads with recent replies
        started_on = timezone.now() - timedelta(days=30)
        posted_on = timezone.now()
        for t in xrange(10):
            thread = testutils.post_thread(forum, started_on=started_on)
            testutils.reply_thread(thread, posted_on=posted_on)

        # post recent threads that will be preserved
        threads = [testutils.post_thread(forum) for t in xrange(10)]

        forum.synchronize()
        self.assertEqual(forum.threads, 20)
        self.assertEqual(forum.posts, 30)

        # run command
        command = pruneforums.Command()

        out = StringIO()
        command.execute(stdout=out)

        forum.synchronize()
        self.assertEqual(forum.threads, 10)
        self.assertEqual(forum.posts, 10)

        for thread in threads:
            forum.thread_set.get(id=thread.id)

        command_output = out.getvalue().strip()
        self.assertEqual(command_output, 'Forums were pruned')
    def test_move_hidden_posts(self):
        """api recjects attempt to move urneadable hidden post"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
                'posts': [testutils.reply_thread(self.thread, is_hidden=True).pk],
            }),
            content_type="application/json",
        )
        self.assertContains(
            response, "You can't move posts the content you can't see.", status_code=400
        )
    def test_move_invisible(self):
        """api validates posts visibility"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
                'posts': [testutils.reply_thread(self.thread, is_unapproved=True).pk],
            }),
            content_type="application/json",
        )
        self.assertContains(
            response, "One or more posts to move could not be found.", status_code=400
        )
    def test_move_limit(self):
        """api rejects more posts than move limit"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
                'posts': list(range(POSTS_LIMIT + 1)),
            }),
            content_type="application/json",
        )
        self.assertContains(
            response, "No more than {} posts can be moved".format(POSTS_LIMIT), status_code=400
        )
Exemple #55
0
    def test_other_thread_isnt_mergeable(self):
        """api validates if other thread can be merged"""
        self.override_acl({'can_merge_threads': 1})
        self.override_other_acl({'can_merge_threads': 0})

        other_thread = testutils.post_thread(self.category_b)

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

        self.assertContains(response,
                            "Other thread can't be merged with.",
                            status_code=400)
    def test_empty_posts_data_json(self):
        """api handles empty json data"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
            }),
            content_type="application/json",
        )

        self.assertContains(
            response, "You have to specify at least one post to move.", status_code=400
        )
    def test_invalid_posts_data(self):
        """api handles invalid data"""
        other_thread = testutils.post_thread(self.category)

        response = self.client.post(
            self.api_link,
            json.dumps({
                'new_thread': other_thread.get_absolute_url(),
                'posts': 'string',
            }),
            content_type="application/json",
        )
        self.assertContains(
            response, "Expected a list of items", status_code=400
        )
Exemple #58
0
    def test_wrong_query(self):
        """api handles query miss"""
        thread = testutils.post_thread(self.category)
        post = testutils.reply_thread(thread, message="Lorem ipsum dolor.")
        self.index_post(post)

        response = self.client.get('%s?q=elit' % self.api_link)
        self.assertEqual(response.status_code, 200)

        reponse_json = response.json()
        self.assertIn('threads', [p['id'] for p in reponse_json])

        for provider in reponse_json:
            if provider['id'] == 'threads':
                self.assertEqual(provider['results']['results'], [])
    def test_category_prune_by_start_date(self):
        """command prunes category content based on start date"""
        category = Category.objects.all_categories()[:1][0]

        category.prune_started_after = 20
        category.save()

        # post old threads with recent replies
        started_on = timezone.now() - timedelta(days=30)
        posted_on = timezone.now()
        for t in range(10):
            thread = testutils.post_thread(category, started_on=started_on)
            testutils.reply_thread(thread, posted_on=posted_on)

        # post recent threads that will be preserved
        threads = [testutils.post_thread(category) for t in range(10)]

        category.synchronize()
        self.assertEqual(category.threads, 20)
        self.assertEqual(category.posts, 30)

        # run command
        command = prunecategories.Command()

        out = StringIO()
        command.execute(stdout=out)

        category.synchronize()
        self.assertEqual(category.threads, 10)
        self.assertEqual(category.posts, 10)

        for thread in threads:
            category.thread_set.get(id=thread.id)

        command_output = out.getvalue().strip()
        self.assertEqual(command_output, 'Categories were pruned')
    def test_validate_posts_same_thread(self):
        """api validates that ids are visible posts"""
        self.override_acl({
            'can_hide_own_posts': 2,
            'can_hide_posts': 2,
        })

        other_thread = testutils.post_thread(category=self.category)
        self.posts.append(
            testutils.reply_thread(other_thread, poster=self.user))

        response = self.delete(self.api_link, [p.id for p in self.posts])
        self.assertContains(response,
                            "One or more posts to delete could not be found.",
                            status_code=403)