|
@@ -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
|
|
|
from misago.users.testutils import AuthenticatedUserTestCase
|
|
|
|
|
|
|
|
@@ -25,28 +25,6 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
}
|
|
|
)
|
|
|
|
|
|
- self.override_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': 0,
|
|
|
- 'can_reply_threads': 0,
|
|
|
- 'can_edit_posts': 1,
|
|
|
- 'can_approve_content': 0,
|
|
|
- 'can_merge_posts': 1,
|
|
|
- })
|
|
|
-
|
|
|
- if extra_acl:
|
|
|
- new_acl['categories'][self.category.pk].update(extra_acl)
|
|
|
-
|
|
|
- override_acl(self.user, new_acl)
|
|
|
-
|
|
|
def test_anonymous_user(self):
|
|
|
"""you need to authenticate to merge posts"""
|
|
|
self.logout_user()
|
|
@@ -61,10 +39,9 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "This action is not available to guests.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": False})
|
|
|
def test_no_permission(self):
|
|
|
"""api validates permission to merge"""
|
|
|
- self.override_acl({'can_merge_posts': 0})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({}),
|
|
@@ -75,6 +52,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "You can't merge posts in this thread.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_empty_data_json(self):
|
|
|
"""api handles empty json data"""
|
|
|
response = self.client.post(
|
|
@@ -85,6 +63,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "You have to select at least two posts to merge.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_empty_data_form(self):
|
|
|
"""api handles empty form data"""
|
|
|
response = self.client.post(self.api_link, {})
|
|
@@ -93,36 +72,34 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "You have to select at least two posts to merge.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_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(), {
|
|
|
"detail": "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(), {
|
|
|
"detail": "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(), {
|
|
|
"detail": "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_merge_posts": True})
|
|
|
def test_no_posts_ids(self):
|
|
|
"""api rejects no posts ids"""
|
|
|
response = self.client.post(
|
|
@@ -137,6 +114,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "You have to select at least two posts to merge.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_invalid_posts_data(self):
|
|
|
"""api handles invalid data"""
|
|
|
response = self.client.post(
|
|
@@ -151,6 +129,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": 'Expected a list of items but got type "str".',
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_invalid_posts_ids(self):
|
|
|
"""api handles invalid post id"""
|
|
|
response = self.client.post(
|
|
@@ -165,6 +144,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "One or more post ids received were invalid.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_one_post_id(self):
|
|
|
"""api rejects one post id"""
|
|
|
response = self.client.post(
|
|
@@ -179,6 +159,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "You have to select at least two posts to merge.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_limit(self):
|
|
|
"""api rejects more posts than merge limit"""
|
|
|
response = self.client.post(
|
|
@@ -193,6 +174,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "No more than %s posts can be merged at single time." % POSTS_LIMIT,
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_event(self):
|
|
|
"""api recjects events"""
|
|
|
event = testutils.reply_thread(self.thread, is_event=True, poster=self.user)
|
|
@@ -209,6 +191,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Events can't be merged.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_notfound_pk(self):
|
|
|
"""api recjects nonexistant pk's"""
|
|
|
response = self.client.post(
|
|
@@ -223,6 +206,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "One or more posts to merge could not be found.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_cross_threads(self):
|
|
|
"""api recjects attempt to merge with post made in other thread"""
|
|
|
other_thread = testutils.post_thread(category=self.category)
|
|
@@ -240,6 +224,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "One or more posts to merge could not be found.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_authenticated_with_guest_post(self):
|
|
|
"""api recjects attempt to merge with post made by deleted user"""
|
|
|
other_post = testutils.reply_thread(self.thread)
|
|
@@ -256,6 +241,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Posts made by different users can't be merged.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_guest_with_authenticated_post(self):
|
|
|
"""api recjects attempt to merge with post made by deleted user"""
|
|
|
other_post = testutils.reply_thread(self.thread)
|
|
@@ -272,6 +258,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Posts made by different users can't be merged.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_guest_posts_different_usernames(self):
|
|
|
"""api recjects attempt to merge posts made by different guests"""
|
|
|
response = self.client.post(
|
|
@@ -289,10 +276,9 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Posts made by different users can't be merged.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_hide_posts": 1})
|
|
|
def test_merge_different_visibility(self):
|
|
|
"""api recjects attempt to merge posts with different visibility"""
|
|
|
- self.override_acl({'can_hide_posts': 1})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({
|
|
@@ -308,10 +294,9 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Posts with different visibility can't be merged.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_approve_content": True})
|
|
|
def test_merge_different_approval(self):
|
|
|
"""api recjects attempt to merge posts with different approval"""
|
|
|
- self.override_acl({'can_approve_content': 1})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({
|
|
@@ -327,7 +312,8 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Posts with different visibility can't be merged.",
|
|
|
})
|
|
|
|
|
|
- def test_closed_thread(self):
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_close_threads": False})
|
|
|
+ def test_closed_thread_no_permission(self):
|
|
|
"""api validates permission to merge in closed thread"""
|
|
|
self.thread.is_closed = True
|
|
|
self.thread.save()
|
|
@@ -347,8 +333,16 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "This thread is closed. You can't merge posts in it.",
|
|
|
})
|
|
|
|
|
|
- # allow closing threads
|
|
|
- self.override_acl({'can_close_threads': 1})
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_close_threads": True})
|
|
|
+ def test_closed_thread(self):
|
|
|
+ """api validates permission to merge in closed thread"""
|
|
|
+ self.thread.is_closed = True
|
|
|
+ self.thread.save()
|
|
|
+
|
|
|
+ posts = [
|
|
|
+ testutils.reply_thread(self.thread, poster=self.user).pk,
|
|
|
+ testutils.reply_thread(self.thread, poster=self.user).pk,
|
|
|
+ ]
|
|
|
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
@@ -357,7 +351,8 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
- def test_closed_category(self):
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_close_threads": False})
|
|
|
+ def test_closed_category_no_permission(self):
|
|
|
"""api validates permission to merge in closed category"""
|
|
|
self.category.is_closed = True
|
|
|
self.category.save()
|
|
@@ -377,8 +372,16 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "This category is closed. You can't merge posts in it.",
|
|
|
})
|
|
|
|
|
|
- # allow closing threads
|
|
|
- self.override_acl({'can_close_threads': 1})
|
|
|
+ @patch_category_acl({"can_merge_posts": True, "can_close_threads": True})
|
|
|
+ def test_closed_category(self):
|
|
|
+ """api validates permission to merge in closed category"""
|
|
|
+ self.category.is_closed = True
|
|
|
+ self.category.save()
|
|
|
+
|
|
|
+ posts = [
|
|
|
+ testutils.reply_thread(self.thread, poster=self.user).pk,
|
|
|
+ testutils.reply_thread(self.thread, poster=self.user).pk,
|
|
|
+ ]
|
|
|
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
@@ -387,6 +390,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_best_answer_first_post(self):
|
|
|
"""api recjects attempt to merge best_answer with first post"""
|
|
|
self.thread.first_post.poster = self.user
|
|
@@ -413,6 +417,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
"detail": "Post marked as best answer can't be merged with thread's first post.",
|
|
|
})
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_posts(self):
|
|
|
"""api merges two posts"""
|
|
|
post_a = testutils.reply_thread(self.thread, poster=self.user, message="Battęry")
|
|
@@ -429,7 +434,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
- self.refresh_thread()
|
|
|
+ self.thread.refresh_from_db()
|
|
|
self.assertEqual(self.thread.replies, thread_replies - 1)
|
|
|
|
|
|
with self.assertRaises(Post.DoesNotExist):
|
|
@@ -438,6 +443,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
merged_post = Post.objects.get(pk=post_a.pk)
|
|
|
self.assertEqual(merged_post.parsed, '%s\n%s' % (post_a.parsed, post_b.parsed))
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_guest_posts(self):
|
|
|
"""api recjects attempt to merge posts made by same guest"""
|
|
|
response = self.client.post(
|
|
@@ -452,10 +458,9 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True, 'can_hide_posts': 1})
|
|
|
def test_merge_hidden_posts(self):
|
|
|
"""api merges two hidden posts"""
|
|
|
- self.override_acl({'can_hide_posts': 1})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({
|
|
@@ -468,10 +473,9 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True, 'can_approve_content': True})
|
|
|
def test_merge_unapproved_posts(self):
|
|
|
"""api merges two unapproved posts"""
|
|
|
- self.override_acl({'can_approve_content': 1})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({
|
|
@@ -484,6 +488,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True, 'can_hide_threads': True})
|
|
|
def test_merge_with_hidden_thread(self):
|
|
|
"""api excludes thread's first post from visibility checks"""
|
|
|
self.thread.first_post.is_hidden = True
|
|
@@ -492,8 +497,6 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
|
|
|
post_visible = testutils.reply_thread(self.thread, poster=self.user, is_hidden=False)
|
|
|
|
|
|
- self.override_acl({'can_hide_threads': 1})
|
|
|
-
|
|
|
response = self.client.post(
|
|
|
self.api_link,
|
|
|
json.dumps({
|
|
@@ -503,6 +506,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_protected(self):
|
|
|
"""api preserves protected status after merge"""
|
|
|
response = self.client.post(
|
|
@@ -520,6 +524,7 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
merged_post = self.thread.post_set.order_by('-id')[0]
|
|
|
self.assertTrue(merged_post.is_protected)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_best_answer(self):
|
|
|
"""api merges best answer with other post"""
|
|
|
best_answer = testutils.reply_thread(self.thread, poster="Bob")
|
|
@@ -539,9 +544,10 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
- self.refresh_thread()
|
|
|
+ self.thread.refresh_from_db()
|
|
|
self.assertEqual(self.thread.best_answer, best_answer)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_best_answer_in(self):
|
|
|
"""api merges best answer into other post"""
|
|
|
other_post = testutils.reply_thread(self.thread, poster="Bob")
|
|
@@ -562,9 +568,10 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
- self.refresh_thread()
|
|
|
+ self.thread.refresh_from_db()
|
|
|
self.assertEqual(self.thread.best_answer, other_post)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_best_answer_in_protected(self):
|
|
|
"""api merges best answer into protected post"""
|
|
|
best_answer = testutils.reply_thread(self.thread, poster="Bob")
|
|
@@ -584,11 +591,14 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
|
|
|
)
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
- self.refresh_thread()
|
|
|
+ self.thread.refresh_from_db()
|
|
|
self.assertEqual(self.thread.best_answer, best_answer)
|
|
|
+
|
|
|
+ self.thread.best_answer.refresh_from_db()
|
|
|
self.assertTrue(self.thread.best_answer.is_protected)
|
|
|
self.assertTrue(self.thread.best_answer_is_protected)
|
|
|
|
|
|
+ @patch_category_acl({"can_merge_posts": True})
|
|
|
def test_merge_remove_reads(self):
|
|
|
"""two posts merge removes read tracker from post"""
|
|
|
post_a = testutils.reply_thread(self.thread, poster=self.user, message="Battęry")
|