Browse Source

fix #912: keep subscriptions when threads are merged

Rafał Pitoń 7 years ago
parent
commit
08b082d10e

+ 17 - 1
misago/threads/signals.py

@@ -20,12 +20,28 @@ move_thread = Signal()
 
 
 @receiver(merge_thread)
-def merge_threads_posts(sender, **kwargs):
+def merge_threads(sender, **kwargs):
     other_thread = kwargs['other_thread']
+
     other_thread.post_set.update(
         category=sender.category,
         thread=sender,
     )
+    other_thread.postedit_set.update(
+        category=sender.category,
+        thread=sender,
+    )
+    other_thread.postlike_set.update(
+        category=sender.category,
+        thread=sender,
+    )
+
+    other_thread.subscription_set.exclude(
+        user__in=sender.subscription_set.values('user'),
+    ).update(
+        category=sender.category,
+        thread=sender,
+    )
 
 
 @receiver(merge_post)

+ 103 - 1
misago/threads/tests/test_thread_merge_api.py

@@ -294,7 +294,7 @@ class ThreadMergeApiTests(ThreadsApiTestCase):
         with self.assertRaises(Thread.DoesNotExist):
             Thread.objects.get(pk=self.thread.pk)
 
-    def test_merge_threads_keep_Reads(self):
+    def test_merge_threads_kept_reads(self):
         """api keeps both threads readtrackers after merge"""
         self.override_acl({'can_merge_threads': 1})
 
@@ -322,6 +322,108 @@ class ThreadMergeApiTests(ThreadsApiTestCase):
         self.assertEqual(postread_set.filter(thread=other_thread).count(), 2)
         self.assertEqual(postread_set.filter(category=self.category_b).count(), 2)
 
+    def test_merge_threads_kept_subs(self):
+        """api keeps other thread's subscription after merge"""
+        self.override_acl({'can_merge_threads': 1})
+
+        self.override_other_acl({'can_merge_threads': 1})
+
+        other_thread = testutils.post_thread(self.category_b)
+
+        self.user.subscription_set.create(
+            thread=self.thread,
+            category=self.thread.category,
+            last_read_on=self.thread.last_post_on,
+            send_email=False,
+        )
+
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=self.thread)
+        self.user.subscription_set.get(category=self.category)
+
+        response = self.client.post(
+            self.api_link, {
+                'other_thread': other_thread.get_absolute_url(),
+            }
+        )
+        self.assertContains(response, other_thread.get_absolute_url(), status_code=200)
+
+        # subscriptions are kept
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=other_thread)
+        self.user.subscription_set.get(category=self.category_b)
+
+    def test_merge_threads_moved_subs(self):
+        """api keeps other thread's subscription after merge"""
+        self.override_acl({'can_merge_threads': 1})
+
+        self.override_other_acl({'can_merge_threads': 1})
+
+        other_thread = testutils.post_thread(self.category_b)
+
+        self.user.subscription_set.create(
+            thread=other_thread,
+            category=other_thread.category,
+            last_read_on=other_thread.last_post_on,
+            send_email=False,
+        )
+
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=other_thread)
+        self.user.subscription_set.get(category=self.category_b)
+
+        response = self.client.post(
+            self.api_link, {
+                'other_thread': other_thread.get_absolute_url(),
+            }
+        )
+        self.assertContains(response, other_thread.get_absolute_url(), status_code=200)
+
+        # subscriptions are kept
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=other_thread)
+        self.user.subscription_set.get(category=self.category_b)
+
+    def test_merge_threads_handle_subs_colision(self):
+        """api resolves conflicting thread subscriptions after merge"""
+        self.override_acl({'can_merge_threads': 1})
+
+        self.override_other_acl({'can_merge_threads': 1})
+
+        self.user.subscription_set.create(
+            thread=self.thread,
+            category=self.thread.category,
+            last_read_on=self.thread.last_post_on,
+            send_email=False,
+        )
+
+        other_thread = testutils.post_thread(self.category_b)
+
+        self.user.subscription_set.create(
+            thread=other_thread,
+            category=other_thread.category,
+            last_read_on=other_thread.last_post_on,
+            send_email=False,
+        )
+
+        self.assertEqual(self.user.subscription_set.count(), 2)
+        self.user.subscription_set.get(thread=self.thread)
+        self.user.subscription_set.get(category=self.category)
+        self.user.subscription_set.get(thread=other_thread)
+        self.user.subscription_set.get(category=self.category_b)
+
+        response = self.client.post(
+            self.api_link, {
+                'other_thread': other_thread.get_absolute_url(),
+            }
+        )
+        self.assertContains(response, other_thread.get_absolute_url(), status_code=200)
+
+        # subscriptions are kept
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=other_thread)
+        self.user.subscription_set.get(category=self.category_b)
+
     def test_merge_threads_kept_poll(self):
         """api merges two threads successfully, keeping poll from old thread"""
         self.override_acl({'can_merge_threads': 1})

+ 18 - 0
misago/threads/tests/test_threads_merge_api.py

@@ -735,6 +735,19 @@ class ThreadsMergeApiTests(ThreadsApiTestCase):
         poststracker.save_read(self.user, self.thread.first_post)
         poststracker.save_read(self.user, thread.first_post)
 
+        self.user.subscription_set.create(
+            thread=self.thread,
+            category=self.thread.category,
+            last_read_on=self.thread.last_post_on,
+            send_email=False,
+        )
+        self.user.subscription_set.create(
+            thread=thread,
+            category=thread.category,
+            last_read_on=thread.last_post_on,
+            send_email=False,
+        )
+
         response = self.client.post(
             self.api_link,
             json.dumps({
@@ -782,6 +795,11 @@ class ThreadsMergeApiTests(ThreadsApiTestCase):
         self.assertEqual(postread_set.filter(thread=new_thread).count(), 2)
         self.assertEqual(postread_set.filter(category=self.category).count(), 2)
 
+        # subscriptions are kept
+        self.assertEqual(self.user.subscription_set.count(), 1)
+        self.user.subscription_set.get(thread=new_thread)
+        self.user.subscription_set.get(category=self.category)
+
     def test_merge_threads_kept_poll(self):
         """api merges two threads successfully, keeping poll from old thread"""
         self.override_acl({'can_merge_threads': True})