forum.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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, Label
  10. from misago.threads.permissions import exclude_invisible_threads
  11. from misago.threads.views.generic.threads import (Helper, Sorting, Threads,
  12. ThreadsView)
  13. __all__ = ['ForumFiltering', 'ForumThreads', 'ForumView']
  14. class ForumFiltering(Helper):
  15. def __init__(self, forum, link_name, link_params):
  16. self.forum = forum
  17. self.link_name = link_name
  18. self.link_params = link_params.copy()
  19. self.filters = self.get_available_filters()
  20. def get_available_filters(self):
  21. filters = []
  22. if self.forum.acl['can_see_all_threads']:
  23. filters.append({
  24. 'type': 'my-threads',
  25. 'name': _("My threads"),
  26. 'is_label': False,
  27. })
  28. if self.forum.acl['can_see_reports']:
  29. filters.append({
  30. 'type': 'reported',
  31. 'name': _("With reported posts"),
  32. 'is_label': False,
  33. })
  34. if self.forum.acl['can_review_moderated_content']:
  35. filters.extend(({
  36. 'type': 'moderated-threads',
  37. 'name': _("Moderated threads"),
  38. 'is_label': False,
  39. },
  40. {
  41. 'type': 'moderated-posts',
  42. 'name': _("With moderated posts"),
  43. 'is_label': False,
  44. }))
  45. for label in self.forum.labels:
  46. filters.append({
  47. 'type': label.slug,
  48. 'name': label.name,
  49. 'is_label': True,
  50. 'css_class': label.css_class,
  51. })
  52. return filters
  53. def clean_kwargs(self, kwargs):
  54. show = kwargs.get('show')
  55. if show:
  56. available_filters = [method['type'] for method in self.filters]
  57. if show in available_filters:
  58. self.show = show
  59. else:
  60. kwargs.pop('show')
  61. else:
  62. self.show = None
  63. return kwargs
  64. def filter(self, threads):
  65. threads.filter(self.show)
  66. def get_filtering_dics(self):
  67. try:
  68. return self._dicts
  69. except AttributeError:
  70. self._dicts = self.create_dicts()
  71. return self._dicts
  72. def create_dicts(self):
  73. dicts = []
  74. if self.forum.acl['can_see_all_threads']:
  75. default_name = _("All threads")
  76. else:
  77. default_name = _("Your threads")
  78. self.link_params.pop('show', None)
  79. dicts.append({
  80. 'type': None,
  81. 'url': reverse(self.link_name, kwargs=self.link_params),
  82. 'name': default_name,
  83. 'is_label': False,
  84. })
  85. for filtering in self.filters:
  86. self.link_params['show'] = filtering['type']
  87. filtering['url'] = reverse(self.link_name, kwargs=self.link_params)
  88. dicts.append(filtering)
  89. return dicts
  90. @property
  91. def is_active(self):
  92. return bool(self.show)
  93. @property
  94. def current(self):
  95. try:
  96. return self._current
  97. except AttributeError:
  98. for filtering in self.get_filtering_dics():
  99. if filtering['type'] == self.show:
  100. self._current = filtering
  101. return filtering
  102. def choices(self):
  103. if self.show:
  104. choices = []
  105. for filtering in self.get_filtering_dics():
  106. if filtering['type'] != self.show:
  107. choices.append(filtering)
  108. return choices
  109. else:
  110. return self.get_filtering_dics()[1:]
  111. class ForumThreads(Threads):
  112. def __init__(self, user, forum):
  113. self.user = user
  114. self.forum = forum
  115. self.queryset = self.make_queryset()
  116. def make_queryset(self):
  117. return exclude_invisible_threads(
  118. self.user, self.forum, self.forum.thread_set)
  119. def filter(self, filter_by):
  120. self.filter_by = filter_by
  121. def sort(self, sort_by):
  122. if sort_by[0] == '-':
  123. weight = '-weight'
  124. else:
  125. weight = 'weight'
  126. self.queryset = self.queryset.order_by(weight, sort_by)
  127. def list(self, page=0):
  128. queryset = self.filter_threads(self.queryset)
  129. announcements_qs = queryset.filter(weight=ANNOUNCEMENT)
  130. threads_qs = queryset.filter(weight__lt=ANNOUNCEMENT)
  131. self._page = paginate(threads_qs, page, 20, 10)
  132. self._paginator = self._page.paginator
  133. threads = []
  134. for announcement in announcements_qs:
  135. threads.append(announcement)
  136. for thread in self._page.object_list:
  137. threads.append(thread)
  138. for thread in threads:
  139. thread.forum = self.forum
  140. self.label_threads(threads, self.forum.labels)
  141. self.make_threads_read_aware(threads)
  142. return threads
  143. def filter_threads(self, queryset):
  144. if self.filter_by == 'my-threads':
  145. return queryset.filter(starter_id=self.user.id)
  146. else:
  147. if self.forum.acl['can_see_own_threads']:
  148. if self.user.is_authenticated():
  149. queryset = queryset.filter(starter_id=self.user.id)
  150. else:
  151. queryset = queryset.filter(starter_id=0)
  152. if self.filter_by == 'reported':
  153. return queryset.filter(has_reported_posts=True)
  154. elif self.filter_by == 'moderated-threads':
  155. return queryset.filter(is_moderated=True)
  156. elif self.filter_by == 'moderated-posts':
  157. return queryset.filter(has_moderated_posts=True)
  158. else:
  159. for label in self.forum.labels:
  160. if label.slug == self.filter_by:
  161. return queryset.filter(label_id=label.pk)
  162. else:
  163. return queryset
  164. error_message = ("threads list has to be loaded via call to list() before "
  165. "pagination data will be available")
  166. @property
  167. def page(self):
  168. try:
  169. return self._page
  170. except AttributeError:
  171. raise RuntimeError(error_message)
  172. @property
  173. def paginator(self):
  174. try:
  175. return self._paginator
  176. except AttributeError:
  177. raise RuntimeError(error_message)
  178. class ForumView(ThreadsView):
  179. """
  180. Basic view for forum threads lists
  181. """
  182. template = 'misago/threads/forum.html'
  183. Threads = ForumThreads
  184. Sorting = Sorting
  185. Filtering = ForumFiltering
  186. def get_default_link_params(self, forum):
  187. message = "forum views have to define get_default_link_params"
  188. raise NotImplementedError(message)
  189. def dispatch(self, request, *args, **kwargs):
  190. forum = self.get_forum(request, **kwargs)
  191. forum.labels = Label.objects.get_forum_labels(forum)
  192. if forum.lft + 1 < forum.rght:
  193. forum.subforums = get_forums_list(request.user, forum)
  194. else:
  195. forum.subforums = []
  196. page_number = kwargs.pop('page', None)
  197. cleaned_kwargs = self.clean_kwargs(request, kwargs)
  198. sorting = self.Sorting(self.link_name, cleaned_kwargs)
  199. cleaned_kwargs = sorting.clean_kwargs(cleaned_kwargs)
  200. filtering = self.Filtering(forum, self.link_name, cleaned_kwargs)
  201. cleaned_kwargs = filtering.clean_kwargs(cleaned_kwargs)
  202. threads = self.Threads(request.user, forum)
  203. sorting.sort(threads)
  204. filtering.filter(threads)
  205. if cleaned_kwargs != kwargs:
  206. return redirect('misago:forum', **cleaned_kwargs)
  207. return self.render(request, {
  208. 'link_name': self.link_name,
  209. 'links_params': cleaned_kwargs,
  210. 'forum': forum,
  211. 'path': get_forum_path(forum),
  212. 'threads': threads.list(page_number),
  213. 'page': threads.page,
  214. 'paginator': threads.paginator,
  215. 'sorting': sorting,
  216. 'filtering': filtering,
  217. })