forum.py 8.0 KB

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