from django.http import Http404 from rest_framework.response import Response from misago.acl import add_acl from misago.categories.models import Category from misago.categories.permissions import allow_see_category, allow_browse_category from misago.core.shortcuts import get_int_or_404, paginate, pagination_dict from misago.readtracker import threadstracker from misago.threads.mixins.threadslists import ThreadsListMixin from misago.threads.permissions.privatethreads import allow_use_private_threads from misago.threads.serializers import ThreadListSerializer from misago.threads.subscriptions import make_subscription_aware from misago.threads.utils import add_categories_to_threads LIST_TYPES = ( 'all', 'my', 'new', 'unread', 'subscribed', 'unapproved', ) class BaseListEndpoint(ThreadsListMixin): serialize_subcategories = True def __call__(self, request): try: page_no = int(request.query_params.get('page', 0)) except (ValueError, TypeError): raise Http404() list_type = request.query_params.get('list') or 'all' if list_type not in LIST_TYPES: raise Http404() categories = self.get_categories(request) category = self.get_category(request, categories) self.allow_see_list(request, category, list_type) subcategories = self.get_subcategories(category, categories) base_queryset = self.get_base_queryset(request, categories, list_type) threads_categories = [category] + subcategories threads_queryset = self.get_threads_queryset(category, base_queryset, threads_categories) page = paginate(threads_queryset, page_no, 24, 6, allow_explicit_first_page=True) response_dict = pagination_dict(page, include_page_range=False) if page.number > 1: threads = list(page.object_list) else: pinned_threads = self.get_pinned_threads(category, base_queryset, threads_categories) threads = list(pinned_threads) + list(page.object_list) if list_type in ('new', 'unread'): # we already know all threads on list are unread threadstracker.make_unread(threads) else: threadstracker.make_threads_read_aware(request.user, threads) add_categories_to_threads(category, categories, threads) if self.serialize_subcategories: response_dict['subcategories'] = [] visible_subcategories = self.get_visible_subcategories(threads, threads_categories) for subcategory in subcategories: if subcategory in visible_subcategories: response_dict['subcategories'].append(subcategory.pk) add_acl(request.user, threads) make_subscription_aware(request.user, threads) response_dict['results'] = ThreadListSerializer(threads, many=True).data return Response(response_dict) class ThreadsListEndpoint(BaseListEndpoint): def get_category(self, request, categories): if request.query_params.get('category'): category_id = get_int_or_404(request.query_params['category']) for category in categories: if category.pk == category_id: if category.level: allow_see_category(request.user, category) allow_browse_category(request.user, category) return category else: raise Http404() # disallow root category access raise Http404() return categories[0] def get_pinned_threads(self, category, queryset, threads_categories): if category.level: return list(queryset.filter(weight=2)) + list(queryset.filter( weight=1, category__in=threads_categories )) else: return queryset.filter(weight=2) def get_threads_queryset(self, category, queryset, threads_categories): if category.level: return queryset.filter( weight=0, category__in=threads_categories, ) else: return queryset.filter( weight__lt=2, category__in=threads_categories, ) threads_list_endpoint = ThreadsListEndpoint() class PrivateThreadsListEndpoint(BaseListEndpoint): def get_category(self, request, categories): allow_use_private_threads(request.user) return Category.objects.private_threads() def get_subcategories(self, category, categories): return [] def get_pinned_threads(self, category, queryset, threads_categories): return [] def get_threads_queryset(self, category, queryset, threads_categories): return queryset.filter(category__in=threads_categories) private_threads_list_endpoint = PrivateThreadsListEndpoint()