Browse Source

Fix remaining posting middlewares

rafalp 6 years ago
parent
commit
b489fdbba6

+ 6 - 4
misago/threads/api/postingendpoint/emailnotification.py

@@ -1,5 +1,6 @@
 from django.utils.translation import gettext as _
 
+from misago.acl import useracl
 from misago.core.mail import build_mail, send_messages
 from misago.threads.permissions import can_see_post, can_see_thread
 
@@ -23,15 +24,16 @@ class EmailNotificationMiddleware(PostingMiddleware):
 
         notifications = []
         for subscription in queryset.iterator():
-            if self.notify_user_of_post(subscription.user):
+            if self.subscriber_can_see_post(subscription.user):
                 notifications.append(self.build_mail(subscription.user))
 
         if notifications:
             send_messages(notifications)
 
-    def notify_user_of_post(self, subscriber):
-        see_thread = can_see_thread(subscriber, self.thread)
-        see_post = can_see_post(subscriber, self.post)
+    def subscriber_can_see_post(self, subscriber):
+        user_acl = useracl.get_user_acl(subscriber, self.request.cache_versions)
+        see_thread = can_see_thread(user_acl, self.thread)
+        see_post = can_see_post(user_acl, self.post)
         return see_thread and see_post
 
     def build_mail(self, subscriber):

+ 4 - 2
misago/threads/api/postingendpoint/floodprotection.py

@@ -13,8 +13,10 @@ MIN_POSTING_PAUSE = 3
 
 class FloodProtectionMiddleware(PostingMiddleware):
     def use_this_middleware(self):
-        return not self.user.acl_cache['can_omit_flood_protection'
-                                       ] and self.mode != PostingEndpoint.EDIT
+        return (
+            not self.user_acl['can_omit_flood_protection'] and
+            self.mode != PostingEndpoint.EDIT
+        )
 
     def interrupt_posting(self, serializer):
         now = timezone.now()

+ 15 - 0
misago/threads/test.py

@@ -28,6 +28,21 @@ def patch_category_acl(acl_patch=None):
     return patch_user_acl(patch_acl)
 
 
+def patch_other_user_category_acl(acl_patch=None):
+    def patch_acl(user, user_acl):
+        if user.slug != "bobbobertson":
+            return
+
+        category = Category.objects.get(slug="first-category")
+        category_acl = user_acl['categories'][category.id]
+        category_acl.update(default_category_acl)
+        if acl_patch:
+            category_acl.update(acl_patch)
+        cleanup_patched_acl(user_acl, category_acl, category)
+
+    return patch_user_acl(patch_acl)
+
+
 def patch_other_category_acl(acl_patch=None):
     def patch_acl(_, user_acl):
         src_category = Category.objects.get(slug="first-category")

+ 34 - 36
misago/threads/tests/test_emailnotification_middleware.py

@@ -7,9 +7,11 @@ from django.urls import reverse
 from django.utils import timezone
 from django.utils.encoding import smart_str
 
-from misago.acl.testutils import override_acl
 from misago.categories.models import Category
 from misago.threads import testutils
+from misago.threads.test import (
+    patch_category_acl, patch_other_user_category_acl
+)
 from misago.users.testutils import AuthenticatedUserTestCase
 
 
@@ -25,7 +27,6 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             category=self.category,
             started_on=timezone.now() - timedelta(seconds=5),
         )
-        self.override_acl()
 
         self.api_link = reverse(
             'misago:api:thread-post-list', kwargs={
@@ -33,37 +34,9 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             }
         )
 
-        self.other_user = UserModel.objects.create_user('Bob', 'bob@boberson.com', 'pass123')
-
-    def override_acl(self):
-        new_acl = deepcopy(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,
-        })
-
-        override_acl(self.user, new_acl)
-
-    def override_other_user_acl(self, hide=False):
-        new_acl = deepcopy(self.other_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,
-        })
-
-        if hide:
-            new_acl['categories'][self.category.pk].update({
-                'can_browse': False,
-            })
-
-        override_acl(self.other_user, new_acl)
+        self.other_user = UserModel.objects.create_user('BobBobertson', 'bob@boberson.com')
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_no_subscriptions(self):
         """no emails are sent because noone subscibes to thread"""
         response = self.client.post(
@@ -75,6 +48,7 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
 
         self.assertEqual(len(mail.outbox), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_poster_not_notified(self):
         """no emails are sent because only poster subscribes to thread"""
         self.user.subscription_set.create(
@@ -93,6 +67,7 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
 
         self.assertEqual(len(mail.outbox), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_other_user_no_email_subscription(self):
         """no emails are sent because subscriber has e-mails off"""
         self.other_user.subscription_set.create(
@@ -111,6 +86,8 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
 
         self.assertEqual(len(mail.outbox), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
+    @patch_other_user_category_acl({"can_see": False})
     def test_other_user_no_permission(self):
         """no emails are sent because subscriber has no permission to read thread"""
         self.other_user.subscription_set.create(
@@ -119,7 +96,6 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             last_read_on=timezone.now(),
             send_email=True,
         )
-        self.override_other_user_acl(hide=True)
 
         response = self.client.post(
             self.api_link, data={
@@ -130,6 +106,29 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
 
         self.assertEqual(len(mail.outbox), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
+    def test_moderation_queue(self):
+        """no emails are sent because new post is moderated"""
+        self.category.require_replies_approval = True
+        self.category.save()
+
+        self.other_user.subscription_set.create(
+            thread=self.thread,
+            category=self.category,
+            last_read_on=timezone.now(),
+            send_email=True,
+        )
+
+        response = self.client.post(
+            self.api_link, data={
+                'post': 'This is test response!',
+            }
+        )
+        self.assertEqual(response.status_code, 200)
+
+        self.assertEqual(len(mail.outbox), 0)
+
+    @patch_category_acl({"can_reply_threads": True})
     def test_other_user_not_read(self):
         """no emails are sent because subscriber didn't read previous post"""
         self.other_user.subscription_set.create(
@@ -138,7 +137,6 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             last_read_on=timezone.now(),
             send_email=True,
         )
-        self.override_other_user_acl()
 
         testutils.reply_thread(self.thread, posted_on=timezone.now())
 
@@ -151,6 +149,7 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
 
         self.assertEqual(len(mail.outbox), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_other_notified(self):
         """email is sent to subscriber"""
         self.other_user.subscription_set.create(
@@ -159,7 +158,6 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             last_read_on=timezone.now(),
             send_email=True,
         )
-        self.override_other_user_acl()
 
         response = self.client.post(
             self.api_link, data={
@@ -183,6 +181,7 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
         last_post = self.thread.post_set.order_by('id').last()
         self.assertIn(last_post.get_absolute_url(), message)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_other_notified_after_reading(self):
         """email is sent to subscriber that had sub updated by read api"""
         self.other_user.subscription_set.create(
@@ -191,7 +190,6 @@ class EmailNotificationTests(AuthenticatedUserTestCase):
             last_read_on=self.thread.last_post_on,
             send_email=True,
         )
-        self.override_other_user_acl()
 
         response = self.client.post(
             self.api_link, data={

+ 18 - 14
misago/threads/tests/test_floodprotection.py

@@ -1,18 +1,17 @@
 from django.urls import reverse
 
-from misago.acl.testutils import override_acl
+from misago.acl.test import patch_user_acl
 from misago.categories.models import Category
 from misago.threads import testutils
 from misago.users.testutils import AuthenticatedUserTestCase
 
 
-class PostMentionsTests(AuthenticatedUserTestCase):
+class FloodProtectionTests(AuthenticatedUserTestCase):
     def setUp(self):
         super().setUp()
 
         self.category = Category.objects.get(slug='first-category')
         self.thread = testutils.post_thread(category=self.category)
-        self.override_acl()
 
         self.post_link = reverse(
             'misago:api:thread-post-list', kwargs={
@@ -20,17 +19,6 @@ class PostMentionsTests(AuthenticatedUserTestCase):
             }
         )
 
-    def override_acl(self):
-        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,
-        })
-
-        override_acl(self.user, new_acl)
-
     def test_flood_has_no_showstoppers(self):
         """endpoint handles posting interruption"""
         response = self.client.post(
@@ -49,3 +37,19 @@ class PostMentionsTests(AuthenticatedUserTestCase):
         self.assertEqual(response.json(), {
             "detail": "You can't post message so quickly after previous one."
         })
+
+    @patch_user_acl({"can_omit_flood_protection": True})
+    def test_user_with_permission_omits_flood_protection(self):
+        response = self.client.post(
+            self.post_link, data={
+                'post': "This is test response!",
+            }
+        )
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.post(
+            self.post_link, data={
+                'post': "This is test response!",
+            }
+        )
+        self.assertEqual(response.status_code, 200)

+ 9 - 7
misago/threads/tests/test_floodprotection_middleware.py

@@ -2,11 +2,12 @@ from datetime import timedelta
 
 from django.utils import timezone
 
-from misago.acl.testutils import override_acl
 from misago.threads.api.postingendpoint import PostingInterrupt
 from misago.threads.api.postingendpoint.floodprotection import FloodProtectionMiddleware
 from misago.users.testutils import AuthenticatedUserTestCase
 
+user_acl = {'can_omit_flood_protection': False}
+
 
 class FloodProtectionMiddlewareTests(AuthenticatedUserTestCase):
     def test_flood_protection_middleware_on_no_posts(self):
@@ -14,7 +15,7 @@ class FloodProtectionMiddlewareTests(AuthenticatedUserTestCase):
         self.user.update_fields = []
         self.assertIsNone(self.user.last_posted_on)
 
-        middleware = FloodProtectionMiddleware(user=self.user)
+        middleware = FloodProtectionMiddleware(user=self.user, user_acl=user_acl)
         middleware.interrupt_posting(None)
 
         self.assertIsNotNone(self.user.last_posted_on)
@@ -26,7 +27,7 @@ class FloodProtectionMiddlewareTests(AuthenticatedUserTestCase):
         original_last_posted_on = timezone.now() - timedelta(days=1)
         self.user.last_posted_on = original_last_posted_on
 
-        middleware = FloodProtectionMiddleware(user=self.user)
+        middleware = FloodProtectionMiddleware(user=self.user, user_acl=user_acl)
         middleware.interrupt_posting(None)
 
         self.assertTrue(self.user.last_posted_on > original_last_posted_on)
@@ -36,12 +37,13 @@ class FloodProtectionMiddlewareTests(AuthenticatedUserTestCase):
         self.user.last_posted_on = timezone.now()
 
         with self.assertRaises(PostingInterrupt):
-            middleware = FloodProtectionMiddleware(user=self.user)
+            middleware = FloodProtectionMiddleware(user=self.user, user_acl=user_acl)
             middleware.interrupt_posting(None)
 
     def test_flood_permission(self):
         """middleware is respects permission to flood for team members"""
-        override_acl(self.user, {'can_omit_flood_protection': True})
-
-        middleware = FloodProtectionMiddleware(user=self.user)
+        can_omit_flood_protection_user_acl = {'can_omit_flood_protection': True}
+        middleware = FloodProtectionMiddleware(
+            user=self.user, user_acl=can_omit_flood_protection_user_acl
+        )
         self.assertFalse(middleware.use_this_middleware())

+ 11 - 14
misago/threads/tests/test_subscription_middleware.py

@@ -1,9 +1,10 @@
 from django.contrib.auth import get_user_model
 from django.urls import reverse
 
-from misago.acl.testutils import override_acl
+from misago.acl.test import patch_user_acl
 from misago.categories.models import Category
 from misago.threads import testutils
+from misago.threads.test import patch_category_acl
 from misago.users.testutils import AuthenticatedUserTestCase
 
 
@@ -14,19 +15,6 @@ class SubscriptionMiddlewareTestCase(AuthenticatedUserTestCase):
     def setUp(self):
         super().setUp()
         self.category = Category.objects.get(slug='first-category')
-        self.override_acl()
-
-    def override_acl(self):
-        new_acl = self.user.acl_cache
-        new_acl['can_omit_flood_protection'] = True
-        new_acl['categories'][self.category.pk].update({
-            'can_see': 1,
-            'can_browse': 1,
-            'can_start_threads': 1,
-            'can_reply_threads': 1,
-        })
-
-        override_acl(self.user, new_acl)
 
 
 class SubscribeStartedThreadTests(SubscriptionMiddlewareTestCase):
@@ -34,6 +22,7 @@ class SubscribeStartedThreadTests(SubscriptionMiddlewareTestCase):
         super().setUp()
         self.api_link = reverse('misago:api:thread-list')
 
+    @patch_category_acl({"can_start_threads": True})
     def test_dont_subscribe(self):
         """middleware makes no subscription to thread"""
         self.user.subscribe_to_started_threads = UserModel.SUBSCRIBE_NONE
@@ -53,6 +42,7 @@ class SubscribeStartedThreadTests(SubscriptionMiddlewareTestCase):
         # user has no subscriptions
         self.assertEqual(self.user.subscription_set.count(), 0)
 
+    @patch_category_acl({"can_start_threads": True})
     def test_subscribe(self):
         """middleware subscribes thread"""
         self.user.subscribe_to_started_threads = UserModel.SUBSCRIBE_NOTIFY
@@ -75,6 +65,7 @@ class SubscribeStartedThreadTests(SubscriptionMiddlewareTestCase):
         self.assertEqual(subscription.category_id, self.category.id)
         self.assertFalse(subscription.send_email)
 
+    @patch_category_acl({"can_start_threads": True})
     def test_email_subscribe(self):
         """middleware subscribes thread with an email"""
         self.user.subscribe_to_started_threads = UserModel.SUBSCRIBE_ALL
@@ -108,6 +99,7 @@ class SubscribeRepliedThreadTests(SubscriptionMiddlewareTestCase):
             }
         )
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_dont_subscribe(self):
         """middleware makes no subscription to thread"""
         self.user.subscribe_to_started_threads = UserModel.SUBSCRIBE_NOTIFY
@@ -124,6 +116,7 @@ class SubscribeRepliedThreadTests(SubscriptionMiddlewareTestCase):
         # user has no subscriptions
         self.assertEqual(self.user.subscription_set.count(), 0)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_subscribe(self):
         """middleware subscribes thread"""
         self.user.subscribe_to_replied_threads = UserModel.SUBSCRIBE_NOTIFY
@@ -142,6 +135,7 @@ class SubscribeRepliedThreadTests(SubscriptionMiddlewareTestCase):
         self.assertEqual(subscription.category_id, self.category.id)
         self.assertFalse(subscription.send_email)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_email_subscribe(self):
         """middleware subscribes thread with an email"""
         self.user.subscribe_to_replied_threads = UserModel.SUBSCRIBE_ALL
@@ -160,6 +154,7 @@ class SubscribeRepliedThreadTests(SubscriptionMiddlewareTestCase):
         self.assertEqual(subscription.category_id, self.category.id)
         self.assertTrue(subscription.send_email)
 
+    @patch_category_acl({"can_reply_threads": True})
     def test_subscribe_with_events(self):
         """middleware omits events when testing for replied thread"""
         self.user.subscribe_to_replied_threads = UserModel.SUBSCRIBE_ALL
@@ -182,6 +177,8 @@ class SubscribeRepliedThreadTests(SubscriptionMiddlewareTestCase):
         self.assertEqual(subscription.category_id, self.category.id)
         self.assertTrue(subscription.send_email)
 
+    @patch_category_acl({"can_reply_threads": True})
+    @patch_user_acl({"can_omit_flood_protection": True})
     def test_dont_subscribe_replied(self):
         """middleware omits threads user already replied"""
         self.user.subscribe_to_replied_threads = UserModel.SUBSCRIBE_ALL