from misago.acl.testutils import override_acl from misago.categories.models import Category from misago.users.testutils import AuthenticatedUserTestCase from .. import testutils from ..models import Post, Thread from ..moderation import threads as threads_moderation from ..moderation.posts import hide_post class MockRequest(object): def __init__(self, user): self.user = user self.user_ip = '127.0.0.1' class ThreadViewTestCase(AuthenticatedUserTestCase): def setUp(self): super(ThreadViewTestCase, self).setUp() self.category = Category.objects.get(slug='first-category') self.thread = testutils.post_thread(category=self.category) def override_acl(self, acl=None): category_acl = self.user.acl['categories'][self.category.pk] category_acl.update({ 'can_see': 1, 'can_browse': 1, 'can_see_all_threads': 1, 'can_see_own_threads': 0, 'can_hide_threads': 0, 'can_approve_content': 0, 'can_edit_posts': 0, 'can_hide_posts': 0, 'can_hide_own_posts': 0, 'can_close_threads': 0, 'post_edit_time': 0, 'can_hide_events': 0, }) if acl: category_acl.update(acl) override_acl(self.user, { 'categories': { self.category.pk: category_acl } }) class ThreadVisibilityTests(ThreadViewTestCase): def test_thread_displays(self): """thread view has no showstoppers""" response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, self.thread.title) def test_view_shows_owner_thread(self): """view handles "owned threads only" """ self.override_acl({ 'can_see_all_threads': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) self.thread.starter = self.user self.thread.save() self.override_acl({ 'can_see_all_threads': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, self.thread.title) def test_view_validates_category_permissions(self): """view validates category visiblity""" self.override_acl({ 'can_see': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) self.override_acl({ 'can_browse': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) def test_view_shows_unapproved_thread(self): """view handles unapproved thread""" self.override_acl({ 'can_approve_content': 0 }) self.thread.is_unapproved = True self.thread.save() response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) # grant permission to see unapproved content self.override_acl({ 'can_approve_content': 1 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, self.thread.title) # make test user thread's owner and remove permission to see unapproved # user should be able to see thread as its author anyway self.thread.starter = self.user self.thread.save() self.override_acl({ 'can_approve_content': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, self.thread.title) def test_view_shows_hidden_thread(self): """view handles hidden thread""" self.override_acl({ 'can_hide_threads': 0 }) self.thread.is_hidden = True self.thread.save() response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) # threads owners are not extempt from hidden threads check self.thread.starter = self.user self.thread.save() response = self.client.get(self.thread.get_absolute_url()) self.assertEqual(response.status_code, 404) # grant permission to see hidden content self.override_acl({ 'can_hide_threads': 1 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, self.thread.title) class ThreadPostsVisibilityTests(ThreadViewTestCase): def test_post_renders(self): """post renders""" post = testutils.reply_thread(self.thread, poster=self.user) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) def test_invalid_post_renders(self): """invalid post renders""" post = testutils.reply_thread(self.thread, poster=self.user) post.parsed = 'fiddled post content' post.save() response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post's contents cannot be displayed.") self.assertNotContains(response, post.parsed) def test_hidden_post_visibility(self): """hidden post renders correctly""" post = testutils.reply_thread(self.thread, message="Hello, I'm hidden post!") hide_post(self.user, post) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is hidden. You cannot not see its contents.") self.assertNotContains(response, post.parsed) # posts authors are not extempt from seeing hidden posts content post.posted_by = self.user post.save() response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is hidden. You cannot not see its contents.") self.assertNotContains(response, post.parsed) # permission to hide own posts isn't enought to see post content self.override_acl({ 'can_hide_own_posts': 1 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is hidden. You cannot not see its contents.") self.assertNotContains(response, post.parsed) # post's content is displayed after permission to see posts is granted self.override_acl({ 'can_hide_posts': 1 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is hidden. Only users with permission may see its contents.") self.assertNotContains(response, "This post is hidden. You cannot not see its contents.") self.assertContains(response, post.parsed) def test_unapproved_post_visibility(self): """unapproved post renders for its author and users with perm to approve content""" post = testutils.reply_thread(self.thread, is_unapproved=True) # post is hdden because we aren't its author nor user with permission to approve response = self.client.get(self.thread.get_absolute_url()) self.assertNotContains(response, post.get_absolute_url()) # post displays because we have permission to approve unapproved content self.override_acl({ 'can_approve_content': 1 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is unapproved.") self.assertContains(response, post.parsed) # post displays because we are its author post.poster = self.user post.save() self.override_acl({ 'can_approve_content': 0 }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertContains(response, "This post is unapproved.") self.assertContains(response, post.parsed) class ThreadEventVisibilityTests(ThreadViewTestCase): def test_thread_events_render(self): """different thread events render""" TEST_ACTIONS = ( (threads_moderation.pin_thread_globally, "Thread has been pinned globally."), (threads_moderation.pin_thread_locally, "Thread has been pinned locally."), (threads_moderation.unpin_thread, "Thread has been unpinned."), (threads_moderation.approve_thread, "Thread has been approved."), (threads_moderation.close_thread, "Thread has been closed."), (threads_moderation.open_thread, "Thread has been opened."), (threads_moderation.hide_thread, "Thread has been made hidden."), (threads_moderation.unhide_thread, "Thread has been revealed."), ) self.thread.is_unapproved = True self.thread.save() for action, message in TEST_ACTIONS: self.override_acl({ 'can_approve_content': 1, 'can_hide_threads': 1, }) self.thread.post_set.filter(is_event=True).delete() action(MockRequest(self.user), self.thread) event = self.thread.post_set.filter(is_event=True)[0] # event renders response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, event.get_absolute_url()) self.assertContains(response, message) # hidden events don't render without permission hide_post(self.user, event) self.override_acl({ 'can_approve_content': 1, 'can_hide_threads': 1, }) response = self.client.get(self.thread.get_absolute_url()) self.assertNotContains(response, event.get_absolute_url()) self.assertNotContains(response, message) # hidden event renders with permission hide_post(self.user, event) self.override_acl({ 'can_approve_content': 1, 'can_hide_threads': 1, 'can_hide_events': 1, }) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, event.get_absolute_url()) self.assertContains(response, message) self.assertContains(response, "Hidden by") def test_changed_thread_title_event_renders(self): """changed thread title event renders""" threads_moderation.change_thread_title(MockRequest(self.user), self.thread, "Lorem renamed ipsum!") event = self.thread.post_set.filter(is_event=True)[0] self.assertEqual(event.event_type, 'changed_title') # event renders response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, event.get_absolute_url()) self.assertContains(response, "title has been changed from") self.assertContains(response, self.thread.title) def test_thread_move_event_renders(self): """moved thread event renders""" self.thread.category = self.thread.category.parent self.thread.save() threads_moderation.move_thread(MockRequest(self.user), self.thread, self.category) event = self.thread.post_set.filter(is_event=True)[0] self.assertEqual(event.event_type, 'moved') # event renders response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, event.get_absolute_url()) self.assertContains(response, "Thread has been moved from") 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") class ThreadAttachmentsViewTests(ThreadViewTestCase): def mock_attachment_cache(self, data): json = { 'url': {}, 'size': 16914, 'filename': 'Archiwum.zip', 'filetype': 'ZIP', 'is_image': False, 'uploaded_on': '2016-10-22T21:17:40.408710Z', 'uploader_name': 'BobBoberson' } json.update(data) return json def test_attachments_display(self): """thread posts show list of attachments below them""" post = self.thread.first_post post.attachments_cache = [ self.mock_attachment_cache({ 'url': { 'index': '/attachment/loremipsum-123/', 'thumb': None, 'uploader': '/user/bobboberson-123/' }, 'filename': 'Archiwum-1.zip', }), self.mock_attachment_cache({ 'url': { 'index': '/attachment/loremipsum-223/', 'thumb': '/attachment/thumb/loremipsum-223/', 'uploader': '/user/bobboberson-223/' }, 'is_image': True, 'filename': 'Archiwum-2.zip' }), self.mock_attachment_cache({ 'url': { 'index': '/attachment/loremipsum-323/', 'thumb': None, 'uploader': '/user/bobboberson-323/' }, 'filename': 'Archiwum-3.zip' }) ] post.save() # attachments render response = self.client.get(self.thread.get_absolute_url()) for attachment in post.attachments_cache: self.assertContains(response, attachment['filename']) self.assertContains(response, attachment['uploader_name']) self.assertContains(response, attachment['url']['index']) self.assertContains(response, attachment['url']['uploader']) if attachment['url']['thumb']: self.assertContains(response, attachment['url']['thumb']) class ThreadPollViewTests(ThreadViewTestCase): def test_poll_voted_display(self): """view has no showstoppers when displaying voted poll""" poll = testutils.post_poll(self.thread, self.user) response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, poll.question) self.assertContains(response, '4 votes') self.assertNotContains(response, 'Save your vote') def test_poll_unvoted_display(self): """view has no showstoppers when displaying poll vote form""" poll = testutils.post_poll(self.thread, self.user) poll.pollvote_set.all().delete() response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, poll.question) self.assertContains(response, 'Save your vote') def test_poll_anonymous_view(self): """view has no showstoppers when displaying poll to anon user""" poll = testutils.post_poll(self.thread, self.user) self.logout_user() response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, poll.question) self.assertContains(response, '4 votes') self.assertNotContains(response, 'Save your vote')