Browse Source

Go to best answer url

Rafał Pitoń 7 years ago
parent
commit
7009d3d49b

+ 4 - 2
misago/threads/api/threadendpoints/patch.py

@@ -17,12 +17,14 @@ from misago.core.apipatch import ApiPatch
 from misago.core.shortcuts import get_int_or_404
 from misago.threads.moderation import threads as moderation
 from misago.threads.participants import (
-    add_participant, change_owner, make_participants_aware, remove_participant)
+    add_participant, change_owner, make_participants_aware, remove_participant
+)
 from misago.threads.permissions import (
     allow_add_participant, allow_add_participants, allow_approve_thread, allow_change_best_answer,
     allow_change_owner, allow_edit_thread, allow_pin_thread, allow_hide_thread, allow_mark_as_best_answer,
     allow_mark_best_answer, allow_move_thread, allow_remove_participant, allow_see_post,
-    allow_start_thread, allow_unhide_thread, allow_unmark_best_answer)
+    allow_start_thread, allow_unhide_thread, allow_unmark_best_answer
+)
 from misago.threads.serializers import ThreadParticipantSerializer
 from misago.threads.validators import validate_title
 

+ 3 - 0
misago/threads/models/thread.py

@@ -246,6 +246,9 @@ class Thread(models.Model):
     def get_last_post_url(self):
         return self.thread_type.get_thread_last_post_url(self)
 
+    def get_best_answer_url(self):
+        return self.thread_type.get_thread_best_answer_url(self)
+
     def get_unapproved_post_url(self):
         return self.thread_type.get_thread_unapproved_post_url(self)
 

+ 1 - 0
misago/threads/serializers/thread.py

@@ -125,6 +125,7 @@ class ThreadSerializer(serializers.ModelSerializer, MutableFields):
             'index': obj.get_absolute_url(),
             'new_post': obj.get_new_post_url(),
             'last_post': obj.get_last_post_url(),
+            'best_answer': obj.get_best_answer_url(),
             'unapproved_post': obj.get_unapproved_post_url(),
             'starter': self.get_starter_url(obj),
             'last_poster': self.get_last_poster_url(obj),

+ 30 - 0
misago/threads/tests/test_gotoviews.py

@@ -202,6 +202,36 @@ class GotoNewTests(GotoViewTestCase):
         )
 
 
+class GotoBestAnswerTests(GotoViewTestCase):
+    def test_view_handles_no_best_answer(self):
+        """if thread has no best answer, redirect to first post"""
+        response = self.client.get(self.thread.get_best_answer_url())
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(
+            response['location'],
+            GOTO_URL % (self.thread.get_absolute_url(), self.thread.first_post_id),
+        )
+
+    def test_view_handles_best_answer(self):
+        """if thread has best answer, redirect to it"""
+        for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL):
+            testutils.reply_thread(self.thread, posted_on=timezone.now())
+
+        best_answer = testutils.reply_thread(self.thread, posted_on=timezone.now())
+        self.thread.set_best_answer(self.user, best_answer)
+        self.thread.save()
+
+        for _ in range(settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL - 1):
+            testutils.reply_thread(self.thread, posted_on=timezone.now())
+
+        response = self.client.get(self.thread.get_best_answer_url())
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(
+            response['location'],
+            GOTO_PAGE_URL % (self.thread.get_absolute_url(), 2, best_answer.pk),
+        )
+
+
 class GotoUnapprovedTests(GotoViewTestCase):
     def grant_permission(self):
         self.user.acl_cache['categories'][self.category.pk]['can_approve_content'] = 1

+ 3 - 0
misago/threads/threadtypes/__init__.py

@@ -26,6 +26,9 @@ class ThreadType(object):
     def get_thread_new_post_url(self, thread):
         return None
 
+    def get_thread_best_answer_url(self, thread):
+        return None
+
     def get_thread_unapproved_post_url(self, thread):
         return None
 

+ 8 - 0
misago/threads/threadtypes/thread.py

@@ -86,6 +86,14 @@ class Thread(ThreadType):
             }
         )
 
+    def get_thread_best_answer_url(self, thread):
+        return reverse(
+            'misago:thread-best-answer', kwargs={
+                'slug': thread.slug,
+                'pk': thread.pk,
+            }
+        )
+
     def get_thread_unapproved_post_url(self, thread):
         return reverse(
             'misago:thread-unapproved', kwargs={

+ 6 - 3
misago/threads/urls/__init__.py

@@ -4,8 +4,9 @@ from misago.conf import settings
 
 from misago.threads.views.attachment import attachment_server
 from misago.threads.views.goto import (
-    ThreadGotoPostView, ThreadGotoLastView, ThreadGotoNewView, ThreadGotoUnapprovedView,
-    PrivateThreadGotoPostView, PrivateThreadGotoLastView, PrivateThreadGotoNewView
+    ThreadGotoPostView, ThreadGotoLastView, ThreadGotoNewView, ThreadGotoBestAnswerView,
+    ThreadGotoUnapprovedView, PrivateThreadGotoPostView, PrivateThreadGotoLastView,
+    PrivateThreadGotoNewView
 )
 from misago.threads.views.list import ForumThreadsList, CategoryThreadsList, PrivateThreadsList
 from misago.threads.views.thread import ThreadView, PrivateThreadView
@@ -90,6 +91,7 @@ def goto_patterns(prefix, **views):
         urls.append(url(url_pattern, post_view.as_view(), name=url_name))
 
     for name, view in views.items():
+        name = name.replace('_', '-')
         url_pattern = r'^%s/(?P<slug>[-a-zA-Z0-9]+)/(?P<pk>\d+)/%s/$' % (prefix[0], name)
         url_name = '%s-%s' % (prefix, name)
         urls.append(url(url_pattern, view.as_view(), name=url_name))
@@ -102,7 +104,8 @@ urlpatterns += goto_patterns(
     post=ThreadGotoPostView,
     last=ThreadGotoLastView,
     new=ThreadGotoNewView,
-    unapproved=ThreadGotoUnapprovedView
+    best_answer=ThreadGotoBestAnswerView,
+    unapproved=ThreadGotoUnapprovedView,
 )
 
 urlpatterns += goto_patterns(

+ 7 - 0
misago/threads/views/goto.py

@@ -105,6 +105,13 @@ class ThreadGotoNewView(GotoView, GetFirstUnreadPostMixin):
         return self.get_first_unread_post(user, posts_queryset)
 
 
+class ThreadGotoBestAnswerView(GotoView):
+    thread = ForumThread
+
+    def get_target_post(self, user, thread, posts_queryset, **kwargs):
+        return thread.best_answer or thread.first_post
+
+
 class ThreadGotoUnapprovedView(GotoView):
     thread = ForumThread