Browse Source

Handle 404 on incorrect page number

Ralfp 12 years ago
parent
commit
5e1dd2b1b4

+ 7 - 41
misago/apps/admin/widgets.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
+from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
@@ -8,6 +9,7 @@ from jinja2 import TemplateNotFound
 import math
 import math
 from misago.forms import Form, FormLayout, FormFields, FormFieldsets
 from misago.forms import Form, FormLayout, FormFields, FormFieldsets
 from misago.messages import Message
 from misago.messages import Message
+from misago.utils.pagination import make_pagination
 
 
 """
 """
 Class widgets
 Class widgets
@@ -207,46 +209,7 @@ class ListWidget(BaseWidget):
         return reverse(self.admin.get_action_attr(self.id, 'route'), kwargs={'page': page})
         return reverse(self.admin.get_action_attr(self.id, 'route'), kwargs={'page': page})
 
 
     def get_pagination(self, total, page):
     def get_pagination(self, total, page):
-        """
-        Return list pagination.
-        A list with three values:
-        - Offset for ORM slicing
-        - Length of slice
-        - no. of prev page (or -1 for first page)
-        - no. of next page (or -1 for last page)
-        - Current page
-        - Pages total
-        """
-        if not self.pagination or total < 0:
-            # Dont do anything if we are not paging
-            return None
-
-        # Set basic pagination, use either Session cache or new page value
-        pagination = {'start': 0, 'stop': 0, 'prev':-1, 'next':-1}
-        if self.request.session.get(self.get_token('pagination')):
-            pagination['start'] = self.request.session.get(self.get_token('pagination'))
-        page = int(page)
-        if page > 0:
-            pagination['start'] = (page - 1) * self.pagination
-
-        # Set page and total stat
-        pagination['page'] = int(pagination['start'] / self.pagination) + 1
-        pagination['total'] = int(math.ceil(total / float(self.pagination)))
-
-        # Fix too large offset
-        if pagination['start'] > total:
-            pagination['start'] = 0
-
-        # Allow prev/next?
-        if total > self.pagination:
-            if pagination['page'] > 1:
-                pagination['prev'] = pagination['page'] - 1
-            if pagination['page'] < pagination['total']:
-                pagination['next'] = pagination['page'] + 1
-
-        # Set stop offset
-        pagination['stop'] = pagination['start'] + self.pagination
-        return pagination
+        return make_pagination(page, total, self.pagination)
 
 
     def get_items(self):
     def get_items(self):
         if self.request.session.get(self.get_token('filter')):
         if self.request.session.get(self.get_token('filter')):
@@ -271,7 +234,10 @@ class ListWidget(BaseWidget):
 
 
         # Set sorting and paginating
         # Set sorting and paginating
         sorting_method = self.get_sorting()
         sorting_method = self.get_sorting()
-        paginating_method = self.get_pagination(items_total, page)
+        try:
+            paginating_method = self.get_pagination(items_total, page)
+        except Http404:
+            return redirect(self.get_url())
 
 
         # List items
         # List items
         items = self.get_items()
         items = self.get_items()

+ 7 - 1
misago/apps/newthreads.py

@@ -1,4 +1,7 @@
 from datetime import timedelta
 from datetime import timedelta
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
@@ -7,7 +10,10 @@ from misago.utils.pagination import make_pagination
 def new_threads(request, page=0):
 def new_threads(request, page=0):
     queryset = Thread.objects.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).filter(start__gte=(timezone.now() - timedelta(days=2)))
     queryset = Thread.objects.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).filter(start__gte=(timezone.now() - timedelta(days=2)))
     items_total = queryset.count();
     items_total = queryset.count();
-    pagination = make_pagination(page, items_total, 30)
+    try:
+        pagination = make_pagination(page, items_total, 30)
+    except Http404:
+        return redirect(reverse('new_threads'))
 
 
     queryset = queryset.order_by('-start').prefetch_related('forum')[pagination['start']:pagination['stop']];
     queryset = queryset.order_by('-start').prefetch_related('forum')[pagination['start']:pagination['stop']];
     if request.settings['avatars_on_threads_list']:
     if request.settings['avatars_on_threads_list']:

+ 7 - 1
misago/apps/popularthreads.py

@@ -1,4 +1,7 @@
 from datetime import timedelta
 from datetime import timedelta
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
@@ -7,7 +10,10 @@ from misago.utils.pagination import make_pagination
 def popular_threads(request, page=0):
 def popular_threads(request, page=0):
     queryset = Thread.objects.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False)
     queryset = Thread.objects.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False)
     items_total = queryset.count();
     items_total = queryset.count();
-    pagination = make_pagination(page, items_total, 30)
+    try:
+        pagination = make_pagination(page, items_total, 30)
+    except Http404:
+        return redirect(reverse('popular_threads'))
 
 
     queryset = queryset.order_by('-score').prefetch_related('forum')[pagination['start']:pagination['stop']];
     queryset = queryset.order_by('-score').prefetch_related('forum')[pagination['start']:pagination['stop']];
     if request.settings['avatars_on_threads_list']:
     if request.settings['avatars_on_threads_list']:

+ 5 - 1
misago/apps/privatethreads/list.py

@@ -1,4 +1,5 @@
 from itertools import chain
 from itertools import chain
+from django.http import Http404
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
@@ -21,7 +22,10 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
             qs_threads = qs_threads.prefetch_related('start_poster', 'last_poster')
             qs_threads = qs_threads.prefetch_related('start_poster', 'last_poster')
 
 
         self.count = qs_threads.count()
         self.count = qs_threads.count()
-        self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+        try:
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+        except Http404:
+            return self.threads_list_redirect()
 
 
         tracker_forum = ThreadsTracker(self.request, self.forum)
         tracker_forum = ThreadsTracker(self.request, self.forum)
         for thread in qs_threads[self.pagination['start']:self.pagination['stop']]:
         for thread in qs_threads[self.pagination['start']:self.pagination['stop']]:

+ 7 - 1
misago/apps/profiles/followers/views.py

@@ -1,3 +1,6 @@
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.template import RequestContext
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
@@ -6,7 +9,10 @@ from misago.utils.pagination import make_pagination
 def followers(request, user, page=0):
 def followers(request, user, page=0):
     queryset = user.follows_set.order_by('username_slug')
     queryset = user.follows_set.order_by('username_slug')
     count = queryset.count()
     count = queryset.count()
-    pagination = make_pagination(page, count, 24)
+    try:
+        pagination = make_pagination(page, count, 24)
+    except Http404:
+        return redirect(reverse('user_followers', kwargs={'user': user.id, 'username': user.username_slug}))
     
     
     return request.theme.render_to_response('profiles/followers.html',
     return request.theme.render_to_response('profiles/followers.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {

+ 8 - 2
misago/apps/profiles/follows/views.py

@@ -1,13 +1,19 @@
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.template import RequestContext
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
 
 
 @profile_view('user_follows')
 @profile_view('user_follows')
 def follows(request, user, page=0):
 def follows(request, user, page=0):
-    
     queryset = user.follows.order_by('username_slug')
     queryset = user.follows.order_by('username_slug')
     count = queryset.count()
     count = queryset.count()
-    pagination = make_pagination(page, count, 24)
+    try:
+        pagination = make_pagination(page, count, 24)
+    except Http404:
+        return redirect(reverse('user_follows', kwargs={'user': user.id, 'username': user.username_slug}))
+
     return request.theme.render_to_response('profiles/follows.html',
     return request.theme.render_to_response('profiles/follows.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                              'profile': user,
                                              'profile': user,

+ 8 - 1
misago/apps/profiles/posts/views.py

@@ -1,3 +1,6 @@
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.template import RequestContext
 from misago.models import Forum
 from misago.models import Forum
@@ -7,7 +10,11 @@ from misago.utils.pagination import make_pagination
 def posts(request, user, page=0):
 def posts(request, user, page=0):
     queryset = user.post_set.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).select_related('thread', 'forum').order_by('-id')
     queryset = user.post_set.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).select_related('thread', 'forum').order_by('-id')
     count = queryset.count()
     count = queryset.count()
-    pagination = make_pagination(page, count, 12)
+    try:
+        pagination = make_pagination(page, count, 12)
+    except Http404:
+        return redirect(reverse('user_posts', kwargs={'user': user.id, 'username': user.username_slug}))
+    
     return request.theme.render_to_response('profiles/posts.html',
     return request.theme.render_to_response('profiles/posts.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {
                                              'profile': user,
                                              'profile': user,

+ 7 - 1
misago/apps/profiles/threads/views.py

@@ -1,3 +1,6 @@
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.decorators import profile_view
 from misago.apps.profiles.template import RequestContext
 from misago.apps.profiles.template import RequestContext
 from misago.models import Forum
 from misago.models import Forum
@@ -7,7 +10,10 @@ from misago.utils.pagination import make_pagination
 def threads(request, user, page=0):
 def threads(request, user, page=0):
     queryset = user.thread_set.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).select_related('start_post', 'forum').order_by('-id')
     queryset = user.thread_set.filter(forum_id__in=Forum.objects.readable_forums(request.acl)).filter(deleted=False).filter(moderated=False).select_related('start_post', 'forum').order_by('-id')
     count = queryset.count()
     count = queryset.count()
-    pagination = make_pagination(page, count, 12)
+    try:
+        pagination = make_pagination(page, count, 12)
+    except Http404:
+        return redirect(reverse('user_threads', kwargs={'user': user.id, 'username': user.username_slug}))
     
     
     return request.theme.render_to_response('profiles/threads.html',
     return request.theme.render_to_response('profiles/threads.html',
                                             context_instance=RequestContext(request, {
                                             context_instance=RequestContext(request, {

+ 7 - 1
misago/apps/profiles/views.py

@@ -1,4 +1,5 @@
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
+from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from misago.apps.errors import error403, error404
 from misago.apps.errors import error403, error404
@@ -71,7 +72,12 @@ def list(request, slug=None, page=1):
         if active_rank:
         if active_rank:
             users = User.objects.filter(rank=active_rank)
             users = User.objects.filter(rank=active_rank)
             items_total = users.count()
             items_total = users.count()
-            pagination = make_pagination(page, items_total, request.settings['profiles_per_list'])
+            try:
+                pagination = make_pagination(page, items_total, request.settings['profiles_per_list'])
+            except Http404:
+                if not default_rank and active_rank:
+                    return redirect(reverse('users', kwargs={'slug': active_rank.slug}))
+                return redirect(reverse('users'))
             users = users.order_by('username_slug')[pagination['start']:pagination['stop']]
             users = users.order_by('username_slug')[pagination['start']:pagination['stop']]
 
 
     return request.theme.render_to_response('profiles/list.html',
     return request.theme.render_to_response('profiles/list.html',

+ 8 - 1
misago/apps/threads/list.py

@@ -1,4 +1,7 @@
 from itertools import chain
 from itertools import chain
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import redirect
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModeration
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
@@ -30,7 +33,11 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
     def fetch_threads(self):
     def fetch_threads(self):
         qs_announcements, qs_threads = self.threads_queryset()
         qs_announcements, qs_threads = self.threads_queryset()
         self.count = qs_threads.count()
         self.count = qs_threads.count()
-        self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+
+        try:
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.threads_per_page)
+        except Http404:
+            return self.threads_list_redirect()
 
 
         tracker_forum = ThreadsTracker(self.request, self.forum)
         tracker_forum = ThreadsTracker(self.request, self.forum)
         for thread in list(chain(qs_announcements, qs_threads[self.pagination['start']:self.pagination['stop']])):
         for thread in list(chain(qs_announcements, qs_threads[self.pagination['start']:self.pagination['stop']])):

+ 0 - 1
misago/apps/threadtype/changelog.py

@@ -10,7 +10,6 @@ from misago.messages import Message
 from misago.models import Forum, Thread, Post, Change
 from misago.models import Forum, Thread, Post, Change
 from misago.utils.datesformats import reldate
 from misago.utils.datesformats import reldate
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
-from misago.utils.pagination import make_pagination
 from misago.apps.threadtype.base import ViewBase
 from misago.apps.threadtype.base import ViewBase
 
 
 class ChangelogBaseView(ViewBase):
 class ChangelogBaseView(ViewBase):

+ 0 - 1
misago/apps/threadtype/jumps.py

@@ -8,7 +8,6 @@ from misago.decorators import block_guest, check_csrf
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread, Post, Karma, WatchedThread
 from misago.models import Forum, Thread, Post, Karma, WatchedThread
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
-from misago.utils.pagination import make_pagination
 from misago.utils.views import json_response
 from misago.utils.views import json_response
 from misago.apps.threadtype.base import ViewBase
 from misago.apps.threadtype.base import ViewBase
 
 

+ 3 - 1
misago/apps/threadtype/list/views.py

@@ -97,7 +97,9 @@ class ThreadsListBaseView(ViewBase):
             self._type_available()
             self._type_available()
             self._fetch_forum()
             self._fetch_forum()
             self._check_permissions()
             self._check_permissions()
-            self.fetch_threads()
+            response = self.fetch_threads()
+            if response:
+                return response
             self.form = None
             self.form = None
             self.make_form()
             self.make_form()
             if self.form:
             if self.form:

+ 9 - 2
misago/apps/threadtype/thread/views.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.forms import ValidationError
 from django.forms import ValidationError
+from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils import timezone
 from django.utils import timezone
@@ -42,7 +43,11 @@ class ThreadBaseView(ViewBase):
         else:
         else:
             self.posts = self.posts.order_by('pk')
             self.posts = self.posts.order_by('pk')
 
 
-        self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.posts_per_page)
+        try:
+            self.pagination = make_pagination(self.kwargs.get('page', 0), self.count, self.request.settings.posts_per_page)
+        except Http404:
+            return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}))
+
         if self.request.settings.posts_per_page < self.count:
         if self.request.settings.posts_per_page < self.count:
             self.posts = self.posts[self.pagination['start']:self.pagination['stop']]
             self.posts = self.posts[self.pagination['start']:self.pagination['stop']]
 
 
@@ -178,7 +183,9 @@ class ThreadBaseView(ViewBase):
             self.fetch_thread()
             self.fetch_thread()
             self.check_forum_type()
             self.check_forum_type()
             self._check_permissions()
             self._check_permissions()
-            self.fetch_posts()
+            response = self.fetch_posts()
+            if response:
+                return response
             self.make_thread_form()
             self.make_thread_form()
             if self.thread_form:
             if self.thread_form:
                 response = self.handle_thread_form()
                 response = self.handle_thread_form()

+ 7 - 1
misago/apps/watchedthreads/views.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.db.models import F
 from django.db.models import F
+from django.http import Http404
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
@@ -20,7 +21,12 @@ def watched_threads(request, page=0, new=False):
     if new:
     if new:
         queryset = queryset.filter(last_read__lt=F('thread__last'))
         queryset = queryset.filter(last_read__lt=F('thread__last'))
     count = queryset.count()
     count = queryset.count()
-    pagination = make_pagination(page, count, request.settings.threads_per_page)
+    try:
+        pagination = make_pagination(page, count, request.settings.threads_per_page)
+    except Http404:
+        if new:
+            return redirect(reverse('watched_threads_new'))
+        return redirect(reverse('watched_threads'))
     queryset = queryset.order_by('-thread__last')
     queryset = queryset.order_by('-thread__last')
     if request.settings.threads_per_page < count:
     if request.settings.threads_per_page < count:
         queryset = queryset[pagination['start']:pagination['stop']]
         queryset = queryset[pagination['start']:pagination['stop']]