Rafał Pitoń 8 лет назад
Родитель
Сommit
83e304c2d9
3 измененных файлов с 75 добавлено и 23 удалено
  1. 2 5
      misago/threads/paginator.py
  2. 57 13
      misago/threads/tests/test_gotoviews.py
  3. 16 5
      misago/threads/views/goto.py

+ 2 - 5
misago/threads/paginator.py

@@ -17,17 +17,14 @@ class PostsPaginator(Paginator):
         if self.count == 0 and not self.allow_empty_first_page:
             return 0
         hits = max(1, self.count - self.orphans)
-        hits += int(ceil(hits / float(self.per_page)))
-        return int(ceil(hits / float(self.per_page)))
+        return int(ceil(hits / float(self.per_page - 1)))
 
     def page(self, number):
         """
         Returns a Page object for the given 1-based page number.
         """
         number = self.validate_number(number)
-        bottom = (number - 1) * self.per_page
-        if number > 1:
-            bottom -= number - 1
+        bottom = (number - 1) * (self.per_page - 1)
         top = bottom + self.per_page
         if top + self.orphans >= self.count:
             top = self.count

+ 57 - 13
misago/threads/tests/test_gotoviews.py

@@ -28,6 +28,9 @@ class GotoPostTests(GotoViewTestCase):
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response['location'], GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id))
 
+        response = self.client.get(response['location'])
+        self.assertContains(response, self.thread.first_post.get_absolute_url())
+
     def test_goto_last_post_on_page(self):
         """last post on page redirect url is valid"""
         for i in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
@@ -37,6 +40,9 @@ class GotoPostTests(GotoViewTestCase):
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response['location'], GOTO_URL % (self.thread.get_absolute_url(), post.pk))
 
+        response = self.client.get(response['location'])
+        self.assertContains(response, post.get_absolute_url())
+
     def test_goto_first_post_on_next_page(self):
         """first post on next page redirect url is valid"""
         for i in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
@@ -46,14 +52,58 @@ class GotoPostTests(GotoViewTestCase):
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk))
 
+        response = self.client.get(response['location'])
+        self.assertContains(response, post.get_absolute_url())
+
+    def test_goto_first_post_on_page_three_out_of_five(self):
+        """first post on next page redirect url is valid"""
+        posts = []
+        for i in range(settings.MISAGO_POSTS_PER_PAGE * 4 - 1):
+            post = testutils.reply_thread(self.thread)
+            posts.append(post)
+
+        post = posts[settings.MISAGO_POSTS_PER_PAGE * 2 - 3]
+
+        response = self.client.get(post.get_absolute_url())
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 3, post.pk))
+
+        response = self.client.get(response['location'])
+        self.assertContains(response, post.get_absolute_url())
+
+    def test_goto_first_event_on_page_three_out_of_five(self):
+        """event redirect url is valid"""
+        posts = []
+        for i in range(settings.MISAGO_POSTS_PER_PAGE * 4 - 1):
+            post = testutils.reply_thread(self.thread)
+            posts.append(post)
+
+        post = posts[settings.MISAGO_POSTS_PER_PAGE * 2 - 2]
+
+        self.thread.has_events = True
+        self.thread.save()
+
+        post.is_event = True
+        post.save()
+
+        response = self.client.get(post.get_absolute_url())
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 3, post.pk))
+
+        response = self.client.get(response['location'])
+        self.assertContains(response, post.get_absolute_url())
+
 
 class GotoLastTests(GotoViewTestCase):
-    def test_goto_first_post(self):
+    def test_goto_last_post(self):
         """first post redirect url is valid"""
         response = self.client.get(self.thread.get_last_post_url())
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response['location'], GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id))
 
+        response = self.client.get(response['location'])
+        self.assertContains(response, self.thread.last_post.get_absolute_url())
+
     def test_goto_last_post_on_page(self):
         """last post on page redirect url is valid"""
         for i in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
@@ -63,14 +113,8 @@ class GotoLastTests(GotoViewTestCase):
         self.assertEqual(response.status_code, 302)
         self.assertEqual(response['location'], GOTO_URL % (self.thread.get_absolute_url(), post.pk))
 
-    def test_goto_first_post_on_next_page(self):
-        """first post on next page redirect url is valid"""
-        for i in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
-            post = testutils.reply_thread(self.thread)
-
-        response = self.client.get(self.thread.get_last_post_url())
-        self.assertEqual(response.status_code, 302)
-        self.assertEqual(response['location'], GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, post.pk))
+        response = self.client.get(response['location'])
+        self.assertContains(response, post.get_absolute_url())
 
 
 class GotoNewTests(GotoViewTestCase):
@@ -134,7 +178,7 @@ class GotoNewTests(GotoViewTestCase):
 
 
 class GotoUnapprovedTests(GotoViewTestCase):
-    def grand_permission(self):
+    def grant_permission(self):
         self.user.acl['categories'][self.category.pk]['can_approve_content'] = 1
         override_acl(self.user, self.user.acl)
 
@@ -143,14 +187,14 @@ class GotoUnapprovedTests(GotoViewTestCase):
         response = self.client.get(self.thread.get_unapproved_post_url())
         self.assertContains(response, "You need permission to approve content", status_code=403)
 
-        self.grand_permission()
+        self.grant_permission()
 
         response = self.client.get(self.thread.get_unapproved_post_url())
         self.assertEqual(response.status_code, 302)
 
     def test_view_handles_no_unapproved_posts(self):
         """if thread has no unapproved posts, redirect to last post"""
-        self.grand_permission()
+        self.grant_permission()
 
         response = self.client.get(self.thread.get_unapproved_post_url())
         self.assertEqual(response.status_code, 302)
@@ -168,7 +212,7 @@ class GotoUnapprovedTests(GotoViewTestCase):
         for i in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
             testutils.reply_thread(self.thread, posted_on=timezone.now())
 
-        self.grand_permission()
+        self.grant_permission()
 
         response = self.client.get(self.thread.get_new_post_url())
         self.assertEqual(response.status_code, 302)

+ 16 - 5
misago/threads/views/goto.py

@@ -36,19 +36,30 @@ class GotoView(View):
         raise NotImplementedError("goto views should define their own get_target_post method")
 
     def compute_post_page(self, target_post, posts_queryset):
+        # filter out events
+        posts_queryset = posts_queryset.filter(is_event=False)
+
         thread_len = posts_queryset.count()
         if thread_len <= settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL:
             return 1 # no chance for post to be on other page than only page
 
         # compute total count of thread pages
-        thread_pages = thread_len // settings.MISAGO_POSTS_PER_PAGE
-        thread_tail = thread_len - thread_pages * settings.MISAGO_POSTS_PER_PAGE
-        if thread_tail > settings.MISAGO_POSTS_TAIL:
-            thread_pages += 1
+        hits = max(1, thread_len - settings.MISAGO_POSTS_TAIL)
+        hits += int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
+        thread_pages = int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
+
+        # is target an event?
+        if target_post.is_event:
+            target_event = target_post
+            previous_posts = posts_queryset.filter(pk__lt=target_event.pk)
+            target_post = previous_posts.order_by('id').last()
 
         # resolve post's page
         post_offset = posts_queryset.filter(pk__lte=target_post.pk).count()
-        post_page = int(ceil(float(post_offset) / settings.MISAGO_POSTS_PER_PAGE))
+        hits = max(1, post_offset)
+        hits += int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
+        post_page = int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
+
         if post_page > thread_pages:
             post_page = thread_pages