goto.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from math import ceil
  2. from django.core.exceptions import PermissionDenied
  3. from django.shortcuts import get_object_or_404, redirect
  4. from django.utils.translation import ugettext as _
  5. from django.views import View
  6. from misago.conf import settings
  7. from misago.threads.permissions import exclude_invisible_posts
  8. from misago.threads.viewmodels import ForumThread, PrivateThread
  9. class GotoView(View):
  10. thread = None
  11. read_aware = False
  12. def get(self, request, pk, slug, **kwargs):
  13. thread = self.get_thread(request, pk, slug).unwrap()
  14. self.test_permissions(request, thread)
  15. posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
  16. target_post = self.get_target_post(thread, posts_queryset.order_by('id'), **kwargs)
  17. target_page = self.compute_post_page(target_post, posts_queryset)
  18. return self.get_redirect(thread, target_post, target_page)
  19. def get_thread(self, request, pk, slug):
  20. return self.thread(request, pk, slug, read_aware=self.read_aware)
  21. def test_permissions(self, request, thread):
  22. pass
  23. def get_target_post(self, thread, posts_queryset):
  24. raise NotImplementedError("goto views should define their own get_target_post method")
  25. def compute_post_page(self, target_post, posts_queryset):
  26. # filter out events
  27. posts_queryset = posts_queryset.filter(is_event=False)
  28. thread_len = posts_queryset.count()
  29. if thread_len <= settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL:
  30. return 1 # no chance for post to be on other page than only page
  31. # compute total count of thread pages
  32. hits = max(1, thread_len - settings.MISAGO_POSTS_TAIL)
  33. hits += int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
  34. thread_pages = int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
  35. # is target an event?
  36. if target_post.is_event:
  37. target_event = target_post
  38. previous_posts = posts_queryset.filter(pk__lt=target_event.pk)
  39. target_post = previous_posts.order_by('id').last()
  40. # resolve post's page
  41. post_offset = posts_queryset.filter(pk__lte=target_post.pk).count()
  42. hits = max(1, post_offset)
  43. hits += int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
  44. post_page = int(ceil(hits / float(settings.MISAGO_POSTS_PER_PAGE)))
  45. if post_page > thread_pages:
  46. post_page = thread_pages
  47. return post_page
  48. def get_redirect(self, thread, target_post, target_page):
  49. thread_url = thread.thread_type.get_thread_absolute_url(thread, target_page)
  50. return redirect('%s#post-%s' % (thread_url, target_post.pk))
  51. class ThreadGotoPostView(GotoView):
  52. thread = ForumThread
  53. def get_target_post(self, thread, posts_queryset, **kwargs):
  54. return get_object_or_404(posts_queryset, pk=kwargs['post'])
  55. class ThreadGotoLastView(GotoView):
  56. thread = ForumThread
  57. def get_target_post(self, thread, posts_queryset, **kwargs):
  58. return posts_queryset.order_by('id').last()
  59. class ThreadGotoNewView(GotoView):
  60. thread = ForumThread
  61. read_aware = True
  62. def get_target_post(self, thread, posts_queryset, **kwargs):
  63. if thread.is_new:
  64. return posts_queryset.filter(
  65. posted_on__gt=thread.last_read_on,
  66. ).order_by('id').first()
  67. else:
  68. return posts_queryset.order_by('id').last()
  69. class ThreadGotoUnapprovedView(GotoView):
  70. thread = ForumThread
  71. def test_permissions(self, request, thread):
  72. if not thread.acl['can_approve']:
  73. raise PermissionDenied(
  74. _(
  75. "You need permission to approve content to "
  76. "be able to go to first unapproved post."
  77. )
  78. )
  79. def get_target_post(self, thread, posts_queryset, **kwargs):
  80. unapproved_post = posts_queryset.filter(
  81. is_unapproved=True,
  82. ).order_by('id').first()
  83. if unapproved_post:
  84. return unapproved_post
  85. else:
  86. return posts_queryset.order_by('id').last()
  87. class PrivateThreadGotoPostView(GotoView):
  88. thread = PrivateThread
  89. def get_target_post(self, thread, posts_queryset, **kwargs):
  90. return get_object_or_404(posts_queryset, pk=kwargs['post'])
  91. class PrivateThreadGotoLastView(GotoView):
  92. thread = PrivateThread
  93. def get_target_post(self, thread, posts_queryset, **kwargs):
  94. return posts_queryset.order_by('id').last()
  95. class PrivateThreadGotoNewView(GotoView):
  96. thread = PrivateThread
  97. read_aware = True
  98. def get_target_post(self, thread, posts_queryset, **kwargs):
  99. if thread.is_new:
  100. return posts_queryset.filter(
  101. posted_on__gt=thread.last_read_on,
  102. ).order_by('id').first()
  103. else:
  104. return posts_queryset.order_by('id').last()