forum.py 9.2 KB

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