Browse Source

Fix post merge api

rafalp 6 years ago
parent
commit
b3dd25a959

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

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

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