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)
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))
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)
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')
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)
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])
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.", })
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)
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, )
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), ])
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."], })
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)
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)
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."})
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")
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 )
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, } )
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), ])
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 )
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 )
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)