Browse Source

Fix posts moving

rafalp 6 years ago
parent
commit
2f0befd230

+ 1 - 1
misago/threads/serializers/moderation.py

@@ -223,7 +223,7 @@ class MovePostsSerializer(serializers.Serializer):
         request = self.context['request']
         request = self.context['request']
         thread = self.context['thread']
         thread = self.context['thread']
 
 
-        posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
+        posts_queryset = exclude_invisible_posts(request.user_acl, thread.category, thread.post_set)
         posts_queryset = posts_queryset.filter(id__in=data).order_by('id')
         posts_queryset = posts_queryset.filter(id__in=data).order_by('id')
 
 
         posts = []
         posts = []

+ 50 - 94
misago/threads/tests/test_thread_postmove_api.py

@@ -2,12 +2,12 @@ import json
 
 
 from django.urls import reverse
 from django.urls import reverse
 
 
-from misago.acl.testutils import override_acl
 from misago.categories.models import Category
 from misago.categories.models import Category
 from misago.readtracker import poststracker
 from misago.readtracker import poststracker
 from misago.threads import testutils
 from misago.threads import testutils
 from misago.threads.models import Thread
 from misago.threads.models import Thread
 from misago.threads.serializers.moderation import POSTS_LIMIT
 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
 from misago.users.testutils import AuthenticatedUserTestCase
 
 
 
 
@@ -25,66 +25,14 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
         )
         )
 
 
         Category(
         Category(
-            name='Category B',
-            slug='category-b',
+            name='Other category',
+            slug='other-category',
         ).insert_at(
         ).insert_at(
             self.category,
             self.category,
             position='last-child',
             position='last-child',
             save=True,
             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, extra_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 extra_acl:
-            other_category_acl.update(extra_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):
     def test_anonymous_user(self):
         """you need to authenticate to move posts"""
         """you need to authenticate to move posts"""
@@ -96,46 +44,43 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "This action is not available to guests.",
             "detail": "This action is not available to guests.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_data(self):
     def test_invalid_data(self):
         """api handles post that is invalid type"""
         """api handles post that is invalid type"""
-        self.override_acl()
         response = self.client.post(self.api_link, '[]', content_type="application/json")
         response = self.client.post(self.api_link, '[]', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
             "detail": "Invalid data. Expected a dictionary, but got list.",
             "detail": "Invalid data. Expected a dictionary, but got list.",
         })
         })
 
 
-        self.override_acl()
         response = self.client.post(self.api_link, '123', content_type="application/json")
         response = self.client.post(self.api_link, '123', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
             "detail": "Invalid data. Expected a dictionary, but got int.",
             "detail": "Invalid data. Expected a dictionary, but got int.",
         })
         })
 
 
-        self.override_acl()
         response = self.client.post(self.api_link, '"string"', content_type="application/json")
         response = self.client.post(self.api_link, '"string"', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
             "detail": "Invalid data. Expected a dictionary, but got str.",
             "detail": "Invalid data. Expected a dictionary, but got str.",
         })
         })
 
 
-        self.override_acl()
         response = self.client.post(self.api_link, 'malformed', content_type="application/json")
         response = self.client.post(self.api_link, 'malformed', content_type="application/json")
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
             "detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)",
             "detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": False})
     def test_no_permission(self):
     def test_no_permission(self):
         """api validates permission to move"""
         """api validates permission to move"""
-        self.override_acl({'can_move_posts': 0})
-
         response = self.client.post(self.api_link, json.dumps({}), content_type="application/json")
         response = self.client.post(self.api_link, json.dumps({}), content_type="application/json")
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
             "detail": "You can't move posts in this thread.",
             "detail": "You can't move posts in this thread.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_no_new_thread_url(self):
     def test_move_no_new_thread_url(self):
         """api validates if new thread url was given"""
         """api validates if new thread url was given"""
         response = self.client.post(self.api_link)
         response = self.client.post(self.api_link)
@@ -144,6 +89,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "Enter link to new thread.",
             "detail": "Enter link to new thread.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_new_thread_url(self):
     def test_invalid_new_thread_url(self):
         """api validates new thread url"""
         """api validates new thread url"""
         response = self.client.post(self.api_link, {
         response = self.client.post(self.api_link, {
@@ -154,6 +100,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "This is not a valid thread link.",
             "detail": "This is not a valid thread link.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_current_new_thread_url(self):
     def test_current_new_thread_url(self):
         """api validates if new thread url points to current thread"""
         """api validates if new thread url points to current thread"""
         response = self.client.post(
         response = self.client.post(
@@ -166,16 +113,14 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "Thread to move posts to is same as current one.",
             "detail": "Thread to move posts to is same as current one.",
         })
         })
 
 
+    @patch_other_category_acl({"can_see": False})
+    @patch_category_acl({"can_move_posts": True})
     def test_other_thread_exists(self):
     def test_other_thread_exists(self):
         """api validates if other thread exists"""
         """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()
+        other_thread = testutils.post_thread(self.other_category)
 
 
         response = self.client.post(self.api_link, {
         response = self.client.post(self.api_link, {
-            'new_thread': other_new_thread,
+            'new_thread': other_thread.get_absolute_url(),
         })
         })
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.json(), {
         self.assertEqual(response.json(), {
@@ -185,11 +130,11 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             ),
             ),
         })
         })
 
 
+    @patch_other_category_acl({"can_browse": False})
+    @patch_category_acl({"can_move_posts": True})
     def test_other_thread_is_invisible(self):
     def test_other_thread_is_invisible(self):
         """api validates if other thread is visible"""
         """api validates if other thread is visible"""
-        self.override_other_acl({'can_see': 0})
-
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
 
 
         response = self.client.post(
         response = self.client.post(
             self.api_link, {
             self.api_link, {
@@ -204,11 +149,11 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             ),
             ),
         })
         })
 
 
+    @patch_other_category_acl({"can_reply_threads": False})
+    @patch_category_acl({"can_move_posts": True})
     def test_other_thread_isnt_replyable(self):
     def test_other_thread_isnt_replyable(self):
         """api validates if other thread can be replied"""
         """api validates if other thread can be replied"""
-        self.override_other_acl({'can_reply_threads': 0})
-
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
 
 
         response = self.client.post(
         response = self.client.post(
             self.api_link, {
             self.api_link, {
@@ -220,6 +165,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You can't move posts to threads you can't reply.",
             "detail": "You can't move posts to threads you can't reply.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_empty_data(self):
     def test_empty_data(self):
         """api handles empty data"""
         """api handles empty data"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -230,6 +176,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "Enter link to new thread.",
             "detail": "Enter link to new thread.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_empty_posts_data_json(self):
     def test_empty_posts_data_json(self):
         """api handles empty json data"""
         """api handles empty json data"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -246,6 +193,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You have to specify at least one post to move.",
             "detail": "You have to specify at least one post to move.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_empty_posts_data_form(self):
     def test_empty_posts_data_form(self):
         """api handles empty form data"""
         """api handles empty form data"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -261,6 +209,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You have to specify at least one post to move.",
             "detail": "You have to specify at least one post to move.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_no_posts_ids(self):
     def test_no_posts_ids(self):
         """api rejects no posts ids"""
         """api rejects no posts ids"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -278,6 +227,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You have to specify at least one post to move.",
             "detail": "You have to specify at least one post to move.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_posts_data(self):
     def test_invalid_posts_data(self):
         """api handles invalid data"""
         """api handles invalid data"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -295,6 +245,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": 'Expected a list of items but got type "str".',
             "detail": 'Expected a list of items but got type "str".',
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_invalid_posts_ids(self):
     def test_invalid_posts_ids(self):
         """api handles invalid post id"""
         """api handles invalid post id"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -312,6 +263,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more post ids received were invalid.",
             "detail": "One or more post ids received were invalid.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_limit(self):
     def test_move_limit(self):
         """api rejects more posts than move limit"""
         """api rejects more posts than move limit"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -329,6 +281,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "No more than %s posts can be moved at single time." % POSTS_LIMIT,
             "detail": "No more than %s posts can be moved at single time." % POSTS_LIMIT,
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_invisible(self):
     def test_move_invisible(self):
         """api validates posts visibility"""
         """api validates posts visibility"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -346,6 +299,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more posts to move could not be found.",
             "detail": "One or more posts to move could not be found.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_other_thread_posts(self):
     def test_move_other_thread_posts(self):
         """api recjects attempt to move other thread's post"""
         """api recjects attempt to move other thread's post"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -363,6 +317,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "One or more posts to move could not be found.",
             "detail": "One or more posts to move could not be found.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_event(self):
     def test_move_event(self):
         """api rejects events move"""
         """api rejects events move"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -380,6 +335,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "Events can't be moved.",
             "detail": "Events can't be moved.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_first_post(self):
     def test_move_first_post(self):
         """api rejects first post move"""
         """api rejects first post move"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -397,6 +353,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You can't move thread's first post.",
             "detail": "You can't move thread's first post.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True})
     def test_move_hidden_posts(self):
     def test_move_hidden_posts(self):
         """api recjects attempt to move urneadable hidden post"""
         """api recjects attempt to move urneadable hidden post"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -414,6 +371,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "You can't move posts the content you can't see.",
             "detail": "You can't move posts the content you can't see.",
         })
         })
 
 
+    @patch_category_acl({"can_move_posts": True, "can_close_threads": False})
     def test_move_posts_closed_thread_no_permission(self):
     def test_move_posts_closed_thread_no_permission(self):
         """api recjects attempt to move posts from closed thread"""
         """api recjects attempt to move posts from closed thread"""
         other_thread = testutils.post_thread(self.category)
         other_thread = testutils.post_thread(self.category)
@@ -421,8 +379,6 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
         self.thread.is_closed = True
         self.thread.is_closed = True
         self.thread.save()
         self.thread.save()
 
 
-        self.override_acl({'can_close_threads': 0})
-
         response = self.client.post(
         response = self.client.post(
             self.api_link,
             self.api_link,
             json.dumps({
             json.dumps({
@@ -436,16 +392,15 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "This thread is closed. You can't move posts in it.",
             "detail": "This thread is closed. You can't move posts in it.",
         })
         })
 
 
+    @patch_other_category_acl({"can_reply_threads": True, "can_close_threads": False})
+    @patch_category_acl({"can_move_posts": True})
     def test_move_posts_closed_category_no_permission(self):
     def test_move_posts_closed_category_no_permission(self):
         """api recjects attempt to move posts from closed thread"""
         """api recjects attempt to move posts from closed thread"""
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
 
 
         self.category.is_closed = True
         self.category.is_closed = True
         self.category.save()
         self.category.save()
 
 
-        self.override_acl({'can_close_threads': 0})
-        self.override_other_acl({'can_reply_threads': 1})
-
         response = self.client.post(
         response = self.client.post(
             self.api_link,
             self.api_link,
             json.dumps({
             json.dumps({
@@ -459,11 +414,11 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             "detail": "This category is closed. You can't move posts in it.",
             "detail": "This category is closed. You can't move posts in it.",
         })
         })
 
 
+    @patch_other_category_acl({"can_reply_threads": True})
+    @patch_category_acl({"can_move_posts": True})
     def test_move_posts(self):
     def test_move_posts(self):
         """api moves posts to other thread"""
         """api moves posts to other thread"""
-        self.override_other_acl({'can_reply_threads': 1})
-
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
 
 
         posts = (
         posts = (
             testutils.reply_thread(self.thread).pk,
             testutils.reply_thread(self.thread).pk,
@@ -472,7 +427,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
             testutils.reply_thread(self.thread).pk,
             testutils.reply_thread(self.thread).pk,
         )
         )
 
 
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 4)
         self.assertEqual(self.thread.replies, 4)
 
 
         response = self.client.post(
         response = self.client.post(
@@ -486,25 +441,25 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
         # replies were moved
         # replies were moved
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 0)
         self.assertEqual(self.thread.replies, 0)
 
 
         other_thread = Thread.objects.get(pk=other_thread.pk)
         other_thread = Thread.objects.get(pk=other_thread.pk)
         self.assertEqual(other_thread.post_set.filter(pk__in=posts).count(), 4)
         self.assertEqual(other_thread.post_set.filter(pk__in=posts).count(), 4)
         self.assertEqual(other_thread.replies, 4)
         self.assertEqual(other_thread.replies, 4)
 
 
+    @patch_other_category_acl({"can_reply_threads": True})
+    @patch_category_acl({"can_move_posts": True})
     def test_move_best_answer(self):
     def test_move_best_answer(self):
         """api moves best answer to other thread"""
         """api moves best answer to other thread"""
-        self.override_other_acl({'can_reply_threads': 1})
-
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
         best_answer = testutils.reply_thread(self.thread)
         best_answer = testutils.reply_thread(self.thread)
 
 
         self.thread.set_best_answer(self.user, best_answer)
         self.thread.set_best_answer(self.user, best_answer)
         self.thread.synchronize()
         self.thread.synchronize()
         self.thread.save()
         self.thread.save()
 
 
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.best_answer, best_answer)
         self.assertEqual(self.thread.best_answer, best_answer)
         self.assertEqual(self.thread.replies, 1)
         self.assertEqual(self.thread.replies, 1)
 
 
@@ -519,7 +474,7 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
         # best_answer was moved and unmarked
         # best_answer was moved and unmarked
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 0)
         self.assertEqual(self.thread.replies, 0)
         self.assertIsNone(self.thread.best_answer)
         self.assertIsNone(self.thread.best_answer)
 
 
@@ -527,18 +482,19 @@ class ThreadPostMoveApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(other_thread.replies, 1)
         self.assertEqual(other_thread.replies, 1)
         self.assertIsNone(other_thread.best_answer)
         self.assertIsNone(other_thread.best_answer)
 
 
+
+    @patch_other_category_acl({"can_reply_threads": True})
+    @patch_category_acl({"can_move_posts": True})
     def test_move_posts_reads(self):
     def test_move_posts_reads(self):
         """api moves posts reads together with posts"""
         """api moves posts reads together with posts"""
-        self.override_other_acl({'can_reply_threads': 1})
-
-        other_thread = testutils.post_thread(self.category_b)
+        other_thread = testutils.post_thread(self.other_category)
 
 
         posts = (
         posts = (
             testutils.reply_thread(self.thread),
             testutils.reply_thread(self.thread),
             testutils.reply_thread(self.thread),
             testutils.reply_thread(self.thread),
         )
         )
 
 
-        self.refresh_thread()
+        self.thread.refresh_from_db()
         self.assertEqual(self.thread.replies, 2)
         self.assertEqual(self.thread.replies, 2)
 
 
         poststracker.save_read(self.user, self.thread.first_post)
         poststracker.save_read(self.user, self.thread.first_post)