list.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from django.http import Http404
  2. from rest_framework.response import Response
  3. from misago.acl import add_acl
  4. from misago.categories.models import CATEGORIES_TREE_ID, Category
  5. from misago.categories.permissions import (
  6. allow_see_category, allow_browse_category)
  7. from misago.categories.serializers import BasicCategorySerializer
  8. from misago.core.shortcuts import (
  9. get_int_or_404, get_object_or_404, paginate, pagination_dict)
  10. from misago.readtracker import threadstracker
  11. from misago.threads.mixins.threadslists import ThreadsListMixin
  12. from misago.threads.serializers import ThreadListSerializer
  13. from misago.threads.subscriptions import make_subscription_aware
  14. from misago.threads.utils import add_categories_to_threads
  15. LIST_TYPES = (
  16. 'all',
  17. 'my',
  18. 'new',
  19. 'unread',
  20. 'subscribed',
  21. )
  22. class BaseListEndpoint(object):
  23. serialize_subcategories = True
  24. def get_final_queryset(self, request, categories, threads_categories,
  25. category, list_type):
  26. return self.get_queryset(request, categories, list_type).filter(
  27. category__in=threads_categories
  28. )
  29. def __call__(self, request):
  30. try:
  31. page = int(request.query_params.get('page', 0))
  32. except ValueError:
  33. raise Http404()
  34. list_type = request.query_params.get('list') or 'all'
  35. if list_type not in LIST_TYPES:
  36. raise Http404()
  37. categories = self.get_categories(request)
  38. category = self.get_category(request, categories)
  39. self.allow_see_list(request, category, list_type)
  40. subcategories = self.get_subcategories(category, categories)
  41. queryset = self.get_queryset(request, categories, list_type)
  42. threads_categories = [category] + subcategories
  43. rest_queryset = self.get_rest_queryset(
  44. category, queryset, threads_categories)
  45. page = paginate(rest_queryset, page, 24, 6,
  46. allow_explicit_first_page=True
  47. )
  48. response_dict = pagination_dict(page, include_page_range=False)
  49. if page.number > 1:
  50. threads = list(page.object_list)
  51. else:
  52. pinned_threads = self.get_pinned_threads(
  53. category, queryset, threads_categories)
  54. threads = list(pinned_threads) + list(page.object_list)
  55. if list_type in ('new', 'unread'):
  56. """we already know all threads on list are unread"""
  57. threadstracker.make_unread(threads)
  58. else:
  59. threadstracker.make_threads_read_aware(
  60. request.user, threads)
  61. add_categories_to_threads(category, categories, threads)
  62. visible_subcategories = []
  63. for thread in threads:
  64. if (thread.top_category and
  65. thread.category in threads_categories and
  66. thread.top_category not in visible_subcategories):
  67. visible_subcategories.append(thread.top_category.pk)
  68. if self.serialize_subcategories:
  69. response_dict['subcategories'] = []
  70. for subcategory in subcategories:
  71. if subcategory.pk in visible_subcategories:
  72. response_dict['subcategories'].append(subcategory.pk)
  73. add_acl(request.user, threads)
  74. make_subscription_aware(request.user, threads)
  75. return Response(dict(
  76. results=ThreadListSerializer(threads, many=True).data,
  77. **response_dict))
  78. class ThreadsListEndpoint(ThreadsListMixin, BaseListEndpoint):
  79. def get_category(self, request, categories):
  80. if request.query_params.get('category'):
  81. category_id = get_int_or_404(request.query_params['category'])
  82. for category in categories:
  83. if category.pk == category_id:
  84. break;
  85. else:
  86. raise Http404()
  87. allow_see_category(request.user, category)
  88. allow_browse_category(request.user, category)
  89. return category
  90. else:
  91. return categories[0]
  92. def get_subcategories(self, category, categories):
  93. subcategories = []
  94. for subcategory in categories:
  95. if category.has_child(subcategory):
  96. subcategories.append(subcategory)
  97. return subcategories
  98. def get_pinned_threads(self, category, queryset, threads_categories):
  99. if category.level:
  100. return list(queryset.filter(weight=2)) + list(queryset.filter(
  101. weight=1,
  102. category__in=threads_categories
  103. ))
  104. else:
  105. return queryset.filter(weight=2)
  106. def get_rest_queryset(self, category, queryset, threads_categories):
  107. if category.level:
  108. return queryset.filter(
  109. weight=0,
  110. category__in=threads_categories,
  111. )
  112. else:
  113. return queryset.filter(
  114. weight__lt=2,
  115. category__in=threads_categories,
  116. )
  117. def get_final_queryset(self, request, categories, threads_categories,
  118. category, list_type):
  119. queryset = self.get_queryset(request, categories, list_type)
  120. if category.level:
  121. announcements = queryset.filter(weight=2)
  122. pinned = queryset.filter(weight=1, category__in=threads_categories)
  123. other = queryset.filter(weight=1, category__in=threads_categories)
  124. return announcements | pinned | other
  125. else:
  126. announcements = queryset.filter(weight=2)
  127. other = queryset.filter(
  128. weight__lt=2,
  129. category__in=threads_categories,
  130. )
  131. return announcements | other
  132. threads_list_endpoint = ThreadsListEndpoint()