Browse Source

Fix threads splitting

rafalp 6 years ago
parent
commit
637ec70846

+ 1 - 1
misago/threads/api/postendpoints/split.py

@@ -16,7 +16,7 @@ def posts_split_endpoint(request, thread):
         data=request.data,
         context={
             'thread': thread,
-            'user': request.user,
+            'user_acl': request.user_acl,
         },
     )
 

+ 52 - 94
misago/threads/tests/test_thread_postsplit_api.py

@@ -2,12 +2,12 @@ import json
 
 from django.urls import reverse
 
-from misago.acl.testutils import override_acl
 from misago.categories.models import Category
 from misago.readtracker import poststracker
 from misago.threads import testutils
 from misago.threads.models import Post, Thread
 from misago.threads.serializers.moderation import POSTS_LIMIT
+from misago.threads.test import patch_category_acl, patch_other_category_acl
 from misago.users.testutils import AuthenticatedUserTestCase
 
 
@@ -29,66 +29,14 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         )
 
         Category(
-            name='Category B',
-            slug='category-b',
+            name='Other category',
+            slug='other-category',
         ).insert_at(
             self.category,
             position='last-child',
             save=True,
         )
-        self.category_b = Category.objects.get(slug='category-b')
-
-        self.override_acl()
-        self.override_other_acl()
-
-    def refresh_thread(self):
-        self.thread = Thread.objects.get(pk=self.thread.pk)
-
-    def override_acl(self, extra_acl=None):
-        new_acl = self.user.acl_cache
-        new_acl['categories'][self.category.pk].update({
-            'can_see': 1,
-            'can_browse': 1,
-            'can_start_threads': 1,
-            'can_reply_threads': 1,
-            'can_edit_posts': 1,
-            'can_approve_content': 0,
-            'can_move_posts': 1,
-        })
-
-        if extra_acl:
-            new_acl['categories'][self.category.pk].update(extra_acl)
-
-        override_acl(self.user, new_acl)
-
-    def override_other_acl(self, acl=None):
-        other_category_acl = self.user.acl_cache['categories'][self.category.pk].copy()
-        other_category_acl.update({
-            'can_see': 1,
-            'can_browse': 1,
-            'can_start_threads': 0,
-            'can_reply_threads': 0,
-            'can_edit_posts': 1,
-            'can_approve_content': 0,
-            'can_move_posts': 1,
-        })
-
-        if acl:
-            other_category_acl.update(acl)
-
-        categories_acl = self.user.acl_cache['categories']
-        categories_acl[self.category_b.pk] = other_category_acl
-
-        visible_categories = [self.category.pk]
-        if other_category_acl['can_see']:
-            visible_categories.append(self.category_b.pk)
-
-        override_acl(
-            self.user, {
-                'visible_categories': visible_categories,
-                'categories': categories_acl,
-            }
-        )
+        self.other_category = Category.objects.get(slug='other-category')
 
     def test_anonymous_user(self):
         """you need to authenticate to split posts"""
@@ -100,16 +48,16 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "This action is not available to guests.",
         })
 
+    @patch_category_acl({"can_move_posts": False})
     def test_no_permission(self):
         """api validates permission to split"""
-        self.override_acl({'can_move_posts': 0})
-
         response = self.client.post(self.api_link, json.dumps({}), content_type="application/json")
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.json(), {
             "detail": "You can't split posts from this thread.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_empty_data(self):
         """api handles empty data"""
         response = self.client.post(self.api_link)
@@ -118,36 +66,34 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "You have to specify at least one post to split.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_data(self):
         """api handles post that is invalid type"""
-        self.override_acl()
         response = self.client.post(self.api_link, '[]', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
             "non_field_errors": ["Invalid data. Expected a dictionary, but got list."],
         })
 
-        self.override_acl()
         response = self.client.post(self.api_link, '123', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
             "non_field_errors": ["Invalid data. Expected a dictionary, but got int."],
         })
 
-        self.override_acl()
         response = self.client.post(self.api_link, '"string"', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
             "non_field_errors": ["Invalid data. Expected a dictionary, but got str."],
         })
 
-        self.override_acl()
         response = self.client.post(self.api_link, 'malformed', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
             "detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_no_posts_ids(self):
         """api rejects no posts ids"""
         response = self.client.post(
@@ -159,6 +105,8 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(response.json(), {
             "detail": "You have to specify at least one post to split.",
         })
+
+    @patch_category_acl({"can_move_posts": True})
     def test_empty_posts_ids(self):
         """api rejects empty posts ids list"""
         response = self.client.post(
@@ -173,6 +121,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "You have to specify at least one post to split.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_posts_data(self):
         """api handles invalid data"""
         response = self.client.post(
@@ -187,6 +136,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": 'Expected a list of items but got type "str".',
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_posts_ids(self):
         """api handles invalid post id"""
         response = self.client.post(
@@ -201,6 +151,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more post ids received were invalid.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_limit(self):
         """api rejects more posts than split limit"""
         response = self.client.post(
@@ -215,6 +166,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "No more than %s posts can be split at single time." % POSTS_LIMIT,
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_invisible(self):
         """api validates posts visibility"""
         response = self.client.post(
@@ -229,6 +181,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more posts to split could not be found.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_event(self):
         """api rejects events split"""
         response = self.client.post(
@@ -243,6 +196,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "Events can't be split.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_first_post(self):
         """api rejects first post split"""
         response = self.client.post(
@@ -257,6 +211,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "You can't split thread's first post.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_hidden_posts(self):
         """api recjects attempt to split urneadable hidden post"""
         response = self.client.post(
@@ -271,13 +226,12 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "You can't split posts the content you can't see.",
         })
 
+    @patch_category_acl({"can_move_posts": True, "can_close_threads": False})
     def test_split_posts_closed_thread_no_permission(self):
         """api recjects attempt to split posts from closed thread"""
         self.thread.is_closed = True
         self.thread.save()
 
-        self.override_acl({'can_close_threads': 0})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -290,13 +244,12 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "This thread is closed. You can't split posts in it.",
         })
 
+    @patch_category_acl({"can_move_posts": True, "can_close_threads": False})
     def test_split_posts_closed_category_no_permission(self):
         """api recjects attempt to split posts from closed thread"""
         self.category.is_closed = True
         self.category.save()
 
-        self.override_acl({'can_close_threads': 0})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -309,6 +262,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "This category is closed. You can't split posts in it.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_other_thread_posts(self):
         """api recjects attempt to split other thread's post"""
         other_thread = testutils.post_thread(self.category)
@@ -325,6 +279,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more posts to split could not be found.",
         })
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_empty_new_thread_data(self):
         """api handles empty form data"""
         response = self.client.post(
@@ -344,6 +299,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_invalid_final_title(self):
         """api rejects split because final thread title was invalid"""
         response = self.client.post(
@@ -364,16 +320,16 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_other_category_acl({"can_see": False})
+    @patch_category_acl({"can_move_posts": True})
     def test_split_invalid_category(self):
         """api rejects split because final category was invalid"""
-        self.override_other_acl({'can_see': 0})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
                 'posts': self.posts,
                 'title': 'Valid thread title',
-                'category': self.category_b.id,
+                'category': self.other_category.id,
             }),
             content_type="application/json",
         )
@@ -386,10 +342,9 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_start_threads": False})
     def test_split_unallowed_start_thread(self):
         """api rejects split because category isn't allowing starting threads"""
-        self.override_acl({'can_start_threads': 0})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -408,6 +363,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_invalid_weight(self):
         """api rejects split because final weight was invalid"""
         response = self.client.post(
@@ -429,6 +385,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_unallowed_global_weight(self):
         """api rejects split because global weight was unallowed"""
         response = self.client.post(
@@ -450,6 +407,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_pin_threads": 0})
     def test_split_unallowed_local_weight(self):
         """api rejects split because local weight was unallowed"""
         response = self.client.post(
@@ -471,10 +429,9 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_pin_threads": 1})
     def test_split_allowed_local_weight(self):
         """api allows local weight"""
-        self.override_acl({'can_pin_threads': 1})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -494,10 +451,9 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_pin_threads": 2})
     def test_split_allowed_global_weight(self):
         """api allows global weight"""
-        self.override_acl({'can_pin_threads': 2})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -517,6 +473,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_close_threads": False})
     def test_split_unallowed_close(self):
         """api rejects split because closing thread was unallowed"""
         response = self.client.post(
@@ -538,10 +495,9 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_close_threads": True})
     def test_split_with_close(self):
         """api allows for closing thread"""
-        self.override_acl({'can_close_threads': True})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -562,6 +518,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_hide_threads": 0})
     def test_split_unallowed_hidden(self):
         """api rejects split because hidden thread was unallowed"""
         response = self.client.post(
@@ -583,10 +540,9 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True, "can_hide_threads": 1})
     def test_split_with_hide(self):
         """api allows for hiding thread"""
-        self.override_acl({'can_hide_threads': True})
-
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -607,9 +563,10 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             }
         )
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split(self):
         """api splits posts to new thread"""
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 2)
 
         response = self.client.post(
@@ -628,12 +585,13 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(split_thread.replies, 1)
 
         # posts were removed from old thread
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 0)
 
         # posts were moved to new thread
         self.assertEqual(split_thread.post_set.filter(pk__in=self.posts).count(), 2)
 
+    @patch_category_acl({"can_move_posts": True})
     def test_split_best_answer(self):
         """api splits best answer to new thread"""
         best_answer = testutils.reply_thread(self.thread)
@@ -642,7 +600,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.thread.synchronize()
         self.thread.save()
 
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.best_answer, best_answer)
         self.assertEqual(self.thread.replies, 3)
 
@@ -658,7 +616,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
 
         # best_answer was moved and unmarked
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 2)
         self.assertIsNone(self.thread.best_answer)
 
@@ -666,18 +624,18 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(split_thread.replies, 0)
         self.assertIsNone(split_thread.best_answer)
 
+    @patch_other_category_acl({
+        'can_start_threads': True,
+        'can_close_threads': True,
+        'can_hide_threads': True,
+        'can_pin_threads': 2,
+    })
+    @patch_category_acl({"can_move_posts": True})
     def test_split_kitchensink(self):
         """api splits posts with kitchensink"""
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 2)
 
-        self.override_other_acl({
-            'can_start_threads': 2,
-            'can_close_threads': True,
-            'can_hide_threads': True,
-            'can_pin_threads': 2,
-        })
-
         poststracker.save_read(self.user, self.thread.first_post)
         for post in self.posts:
             poststracker.save_read(self.user, Post.objects.select_related().get(pk=post))
@@ -687,7 +645,7 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             json.dumps({
                 'posts': self.posts,
                 'title': 'Split thread',
-                'category': self.category_b.id,
+                'category': self.other_category.id,
                 'weight': 2,
                 'is_closed': 1,
                 'is_hidden': 1,
@@ -697,14 +655,14 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
 
         # thread was created
-        split_thread = self.category_b.thread_set.get(slug='split-thread')
+        split_thread = self.other_category.thread_set.get(slug='split-thread')
         self.assertEqual(split_thread.replies, 1)
         self.assertEqual(split_thread.weight, 2)
         self.assertTrue(split_thread.is_closed)
         self.assertTrue(split_thread.is_hidden)
 
         # posts were removed from old thread
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 0)
 
         # posts were moved to new thread