lists.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. from django.conf import settings
  2. from django.core.urlresolvers import reverse
  3. from django.http import Http404
  4. from django.shortcuts import render
  5. from django.views.generic import View
  6. from django.utils.translation import ugettext_lazy
  7. from misago.acl import add_acl
  8. from misago.categories.models import Category
  9. from misago.categories.permissions import allow_see_category, allow_browse_category
  10. from misago.categories.serializers import IndexCategorySerializer
  11. from misago.core.shortcuts import paginate, pagination_dict, validate_slug
  12. from misago.readtracker import threadstracker
  13. from misago.threads.mixins.threadslist import ThreadsListMixin
  14. from misago.threads.permissions.privatethreads import allow_use_private_threads
  15. from misago.threads.serializers import ThreadListSerializer
  16. from misago.threads.subscriptions import make_subscription_aware
  17. from misago.threads.utils import add_categories_to_threads
  18. LISTS_NAMES = {
  19. 'all': None,
  20. 'my': ugettext_lazy("Your threads"),
  21. 'new': ugettext_lazy("New threads"),
  22. 'unread': ugettext_lazy("Unread threads"),
  23. 'subscribed': ugettext_lazy("Subscribed threads"),
  24. 'unapproved': ugettext_lazy("Unapproved content"),
  25. }
  26. class BaseList(View):
  27. template_name = 'misago/threadslist/threads.html'
  28. preloaded_data_prefix = ''
  29. def get(self, request, list_type=None, **kwargs):
  30. try:
  31. page = int(request.GET.get('page', 0))
  32. except (ValueError, TypeError):
  33. raise Http404()
  34. categories = self.get_categories(request)
  35. category = self.get_category(request, categories, **kwargs)
  36. self.allow_see_list(request, category, list_type)
  37. subcategories = self.get_subcategories(category, categories)
  38. base_queryset = self.get_base_queryset(request, categories, list_type)
  39. threads_categories = [category] + subcategories
  40. threads_queryset = self.get_threads_queryset(base_queryset, threads_categories)
  41. list_page = paginate(threads_queryset, page, 24, 6)
  42. paginator = pagination_dict(list_page, include_page_range=False)
  43. if list_page.number > 1:
  44. threads = list(list_page.object_list)
  45. else:
  46. pinned_threads = self.get_pinned_threads(base_queryset, threads_categories)
  47. threads = list(pinned_threads) + list(list_page.object_list)
  48. if list_type in ('new', 'unread'):
  49. # we already know all threads on list are unread
  50. threadstracker.make_unread(threads)
  51. else:
  52. threadstracker.make_threads_read_aware(request.user, threads)
  53. add_categories_to_threads(category, categories, threads)
  54. category.subcategories = []
  55. visible_subcategories = self.get_visible_subcategories(threads, threads_categories)
  56. for subcategory in subcategories:
  57. if subcategory in visible_subcategories:
  58. category.subcategories.append(subcategory)
  59. add_acl(request.user, threads)
  60. make_subscription_aware(request.user, threads)
  61. frontend_context_data = self.get_frontend_context(request, category, categories, threads, paginator)
  62. request.frontend_context.update(frontend_context_data)
  63. context_data = self.get_context_data(request, category, list_type, threads, paginator)
  64. return render(request, self.template_name, context_data)
  65. def get_pinned_threads(self, request, queryset):
  66. return []
  67. def get_threads_queryset(self, queryset, threads_categories):
  68. return queryset.filter(category__in=threads_categories)
  69. def get_frontend_context(self, request, category, categories, threads, paginator):
  70. context = {
  71. 'THREADS': {
  72. 'results': ThreadListSerializer(threads, many=True).data,
  73. 'subcategories': [c.pk for c in category.subcategories]
  74. },
  75. 'CATEGORIES': IndexCategorySerializer(categories, many=True).data
  76. }
  77. context['THREADS'].update(paginator)
  78. return context
  79. def get_context_data(self, request, category, list_type, threads, paginator):
  80. return {
  81. 'category': category,
  82. 'list_name': LISTS_NAMES[list_type],
  83. 'list_type': list_type,
  84. 'threads': threads,
  85. 'paginator': paginator
  86. }
  87. class CategoryThreadsList(BaseList, ThreadsListMixin):
  88. template_name = 'misago/threadslist/category.html'
  89. preloaded_data_prefix = 'CATEGORY_'
  90. def get_category(self, request, categories, **kwargs):
  91. for category in categories:
  92. # pylint
  93. if category.pk == int(kwargs['pk']):
  94. if not category.level:
  95. raise Http404()
  96. allow_see_category(request.user, category)
  97. allow_browse_category(request.user, category)
  98. validate_slug(category, kwargs['slug'])
  99. return category
  100. raise Http404()
  101. def get_pinned_threads(self, queryset, threads_categories):
  102. return list(queryset.filter(weight=2)) + list(queryset.filter(
  103. weight=1,
  104. category__in=threads_categories
  105. ))
  106. def get_threads_queryset(self, queryset, threads_categories):
  107. return queryset.filter(
  108. weight=0,
  109. category__in=threads_categories,
  110. )
  111. def get_frontend_context(self, request, category, categories, *args):
  112. context = super(CategoryThreadsList, self).get_frontend_context(request, category, categories, *args)
  113. if categories[0].special_role:
  114. context['CATEGORIES'][0]['special_role'] = True
  115. context.update({
  116. 'THREADS_API': reverse('misago:api:thread-list'),
  117. 'MERGE_THREADS_API': reverse('misago:api:thread-merge'),
  118. })
  119. return context
  120. class ThreadsList(CategoryThreadsList):
  121. template_name = 'misago/threadslist/threads.html'
  122. def get_category(self, request, categories, **kwargs):
  123. return categories[0]
  124. def get_pinned_threads(self, queryset, threads_categories):
  125. return queryset.filter(weight=2)
  126. def get_threads_queryset(self, queryset, threads_categories):
  127. return queryset.filter(
  128. weight__lt=2,
  129. category__in=threads_categories,
  130. )
  131. def get_context_data(self, *args):
  132. context = super(ThreadsList, self).get_context_data(*args)
  133. context['is_index'] = not settings.MISAGO_CATEGORIES_ON_INDEX
  134. return context
  135. class PrivateThreadsList(BaseList):
  136. template_name = 'misago/threadslist/private_threads.html'
  137. preloaded_data_prefix = 'PRIVATE_'
  138. def get_base_queryset(self, request, categories, list_type):
  139. raise NotImplementedError('Private Threads List is not implemented yet!')
  140. def get_categories(self, request):
  141. return [Category.objects.private_threads()]
  142. def get_category(self, request, **kwargs):
  143. allow_use_private_threads(request.user)
  144. return Category.objects.private_threads()
  145. def get_subcategories(self, category, categories):
  146. return []