forum.py 9.9 KB

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