threadslists.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. from django.core.urlresolvers import reverse
  2. from django.db.models import Q
  3. from django.shortcuts import redirect
  4. from django.utils.translation import ugettext_lazy, ugettext as _
  5. from misago.core.shortcuts import paginate
  6. from misago.forums.lists import get_forums_list, get_forum_path
  7. from misago.threads.posting import (PostingInterrupt, EditorFormset,
  8. START, REPLY, EDIT)
  9. from misago.threads.models import ANNOUNCEMENT, Thread
  10. from misago.threads.views.generic.base import ViewBase
  11. __all__ = ['OrderThreadsMixin', 'ThreadsView', 'ForumView']
  12. class OrderThreadsMixin(object):
  13. order_by = (
  14. ('recently-replied', ugettext_lazy("Recently replied")),
  15. ('last-replied', ugettext_lazy("Last replied")),
  16. ('most-replied', ugettext_lazy("Most replied")),
  17. ('least-replied', ugettext_lazy("Least replied")),
  18. ('newest', ugettext_lazy("Newest")),
  19. ('oldest', ugettext_lazy("Oldest")),
  20. )
  21. def get_ordering(self, kwargs):
  22. if kwargs.get('sort') in [o[0] for o in self.order_by]:
  23. return kwargs.get('sort')
  24. else:
  25. return self.order_by[0][0]
  26. def is_ordering_default(self, order_by):
  27. return self.order_by[0][0] == order_by
  28. def get_ordering_name(self, order_by):
  29. for ordering in self.order_by:
  30. if ordering[0] == order_by:
  31. return ordering[1]
  32. def get_orderings_dicts(self, exclude_ordering, links_params):
  33. url_kwargs = links_params.copy()
  34. dicts = []
  35. for ordering in self.order_by:
  36. if not dicts:
  37. url_kwargs.pop('sort', None)
  38. else:
  39. url_kwargs['sort'] = ordering[0]
  40. if ordering[0] != exclude_ordering:
  41. dicts.append({
  42. 'url': reverse(self.link_name, kwargs=url_kwargs),
  43. 'name': ordering[1],
  44. })
  45. return dicts
  46. class FilterThreadsMixin(object):
  47. def get_filter_name(self, filters, filter_by):
  48. if filters:
  49. if filter_by:
  50. for filtering in filters:
  51. if filtering[0] == filter_by:
  52. return filtering[1]
  53. else:
  54. return _("All threads")
  55. else:
  56. return None
  57. def get_filters_dicts(self, filters, exclude_filter, links_params):
  58. url_kwargs = links_params.copy()
  59. dicts = []
  60. if filters and exclude_filter:
  61. url_kwargs.pop('show', None)
  62. dicts.append({
  63. 'url': reverse(self.link_name, kwargs=url_kwargs),
  64. 'name': _("All threads"),
  65. })
  66. for filtering in filters:
  67. if filtering[0] != exclude_filter:
  68. url_kwargs['show'] = filtering[0]
  69. dicts.append({
  70. 'url': reverse(self.link_name, kwargs=url_kwargs),
  71. 'name': filtering[1],
  72. })
  73. return dicts
  74. class ThreadsView(ViewBase):
  75. def get_threads(self, request, kwargs):
  76. queryset = self.get_threads_queryset(request, forum)
  77. threads_qs = queryset.filter(weight__lt=ANNOUNCEMENT)
  78. threads_qs = threads_qs.order_by('-weight', '-last_post_id')
  79. page = paginate(threads_qs, kwargs.get('page', 0), 30, 10)
  80. threads = []
  81. for announcement in queryset.filter(weight=ANNOUNCEMENT):
  82. threads.append(announcement)
  83. for thread in page.object_list:
  84. threads.append(thread)
  85. for thread in threads:
  86. thread.forum = forum
  87. return page, threads
  88. def get_threads_queryset(self, request):
  89. return forum.thread_set.all().order_by('-last_post_id')
  90. def add_threads_reads(self, request, threads):
  91. for thread in threads:
  92. thread.is_new = False
  93. import random
  94. for thread in threads:
  95. thread.is_new = random.choice((True, False))
  96. class ForumView(FilterThreadsMixin, OrderThreadsMixin, ThreadsView):
  97. """
  98. Basic view for threads lists
  99. """
  100. template = 'misago/threads/list.html'
  101. def get_threads(self, request, forum, kwargs,
  102. order_by=None, filter_by=None):
  103. org_queryset = self.get_threads_queryset(request, forum)
  104. queryset = self.filter_all_querysets(request, forum, org_queryset)
  105. queryset = self.set_custom_filter(request, queryset, filter_by)
  106. announcements_qs = queryset.filter(weight=ANNOUNCEMENT)
  107. threads_qs = queryset.filter(weight__lt=ANNOUNCEMENT)
  108. threads_qs = self.filter_threads_queryset(request, forum, threads_qs)
  109. threads_qs, announcements_qs = self.order_querysets(
  110. order_by, threads_qs, announcements_qs)
  111. page = paginate(threads_qs, kwargs.get('page', 0), 20, 10)
  112. threads = []
  113. for announcement in announcements_qs:
  114. threads.append(announcement)
  115. for thread in page.object_list:
  116. threads.append(thread)
  117. for thread in threads:
  118. thread.forum = forum
  119. return page, threads
  120. def order_querysets(self, order_by, threads, announcements):
  121. if order_by == 'recently-replied':
  122. threads = threads.order_by('-weight', '-last_post')
  123. announcements = announcements.order_by('-last_post')
  124. if order_by == 'last-replied':
  125. threads = threads.order_by('weight', 'last_post')
  126. announcements = announcements.order_by('last_post')
  127. if order_by == 'most-replied':
  128. threads = threads.order_by('-weight', '-replies')
  129. announcements = announcements.order_by('-replies')
  130. if order_by == 'least-replied':
  131. threads = threads.order_by('weight', 'replies')
  132. announcements = announcements.order_by('replies')
  133. if order_by == 'newest':
  134. threads = threads.order_by('-weight', '-id')
  135. announcements = announcements.order_by('-id')
  136. if order_by == 'oldest':
  137. threads = threads.order_by('weight', 'id')
  138. announcements = announcements.order_by('id')
  139. return threads, announcements
  140. def filter_all_querysets(self, request, forum, queryset):
  141. if request.user.is_authenticated():
  142. condition_author = Q(starter_id=request.user.id)
  143. can_mod = forum.acl['can_review_moderated_content']
  144. can_hide = forum.acl['can_hide_threads']
  145. if not can_mod and not can_hide:
  146. condition = Q(is_moderated=False) & Q(is_hidden=False)
  147. queryset = queryset.filter(condition_author | condition)
  148. elif not can_mod:
  149. condition = Q(is_moderated=False)
  150. queryset = queryset.filter(condition_author | condition)
  151. elif not can_hide:
  152. condition = Q(is_hidden=False)
  153. queryset = queryset.filter(condition_author | condition)
  154. else:
  155. if not forum.acl['can_review_moderated_content']:
  156. queryset = queryset.filter(is_moderated=False)
  157. if not forum.acl['can_hide_threads']:
  158. queryset = queryset.filter(is_hidden=False)
  159. return queryset
  160. def filter_threads_queryset(self, request, forum, queryset):
  161. if forum.acl['can_see_own_threads']:
  162. if request.user.is_authenticated():
  163. queryset = queryset.filter(starter_id=request.user.id)
  164. else:
  165. queryset = queryset.filter(starter_id=0)
  166. return queryset
  167. def set_custom_filter(self, request, queryset, filter_by):
  168. if filter_by == 'my-threads':
  169. return queryset.filter(starter_id=request.user.id)
  170. elif filter_by == 'reported':
  171. return queryset.filter(has_reported_posts=True)
  172. elif filter_by == 'moderated-threads':
  173. return queryset.filter(is_moderated=True)
  174. elif filter_by == 'moderated-posts':
  175. return queryset.filter(has_moderated_posts=True)
  176. else:
  177. return queryset
  178. def get_threads_queryset(self, request, forum):
  179. return forum.thread_set.all().order_by('-last_post_id')
  180. def get_default_link_params(self, forum):
  181. message = "forum views have to define get_default_link_params"
  182. raise NotImplementedError(message)
  183. def get_available_filters(self, request, forum):
  184. filters = []
  185. if request.user.is_authenticated():
  186. if forum.acl['can_see_all_threads']:
  187. filters.append(('my-threads', _("My threads")))
  188. if forum.acl['can_see_reports']:
  189. filters.append(('reported', _("With reported posts")))
  190. if forum.acl['can_review_moderated_content']:
  191. filters.extend((
  192. ('moderated-threads', _("Moderated threads")),
  193. ('moderated-posts', _("With moderated posts")),
  194. ))
  195. return filters
  196. def dispatch(self, request, *args, **kwargs):
  197. forum = self.get_forum(request, **kwargs)
  198. links_params = self.get_default_link_params(forum)
  199. if forum.lft + 1 < forum.rght:
  200. forum.subforums = get_forums_list(request.user, forum)
  201. else:
  202. forum.subforums = []
  203. order_by = self.get_ordering(kwargs)
  204. if self.is_ordering_default(kwargs.get('sort')):
  205. kwargs.pop('sort')
  206. return redirect('misago:forum', **kwargs)
  207. elif not self.is_ordering_default(order_by):
  208. links_params['sort'] = order_by
  209. available_filters = self.get_available_filters(request, forum)
  210. if available_filters and kwargs.get('show'):
  211. filter_methods = [f[0] for f in available_filters]
  212. if kwargs.get('show') not in filter_methods:
  213. kwargs.pop('show')
  214. return redirect('misago:forum', **kwargs)
  215. else:
  216. filter_by = kwargs.get('show')
  217. links_params['show'] = filter_by
  218. else:
  219. filter_by = None
  220. page, threads = self.get_threads(
  221. request, forum, kwargs, order_by, filter_by)
  222. self.add_threads_reads(request, threads)
  223. return self.render(request, {
  224. 'forum': forum,
  225. 'path': get_forum_path(forum),
  226. 'page': page,
  227. 'paginator': page.paginator,
  228. 'threads': threads,
  229. 'link_name': self.link_name,
  230. 'links_params': links_params,
  231. 'filter_name': self.get_filter_name(available_filters, filter_by),
  232. 'filters': self.get_filters_dicts(
  233. available_filters, filter_by, links_params),
  234. 'order_name': self.get_ordering_name(order_by),
  235. 'order_by': self.get_orderings_dicts(order_by, links_params),
  236. })