threads.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. from django.contrib import messages
  2. from django.core.urlresolvers import reverse
  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.readtracker import threadstracker
  7. from misago.threads.models import Label
  8. from misago.threads.moderation import ModerationError
  9. from misago.threads.views.generic.base import ViewBase
  10. __all__ = ['Actions', 'Sorting', 'Threads', 'ThreadsView']
  11. class Actions(object):
  12. select_threads_message = ugettext_lazy(
  13. "You have to select at least one thread")
  14. def __init__(self, **kwargs):
  15. if kwargs.get('user').is_authenticated():
  16. self.available_actions = self.get_available_actions(kwargs)
  17. else:
  18. self.available_actions = []
  19. self.selected_ids = []
  20. def get_available_actions(self, kwargs):
  21. raise NotImplementedError("get_available_actions has to return list "
  22. "of dicts with allowed actions")
  23. def resolve_action(self, request):
  24. action_name = request.get_list('thread')
  25. if ':' in action_name:
  26. action_name, action_arg = action_name.split(':')
  27. else:
  28. action_arg = None
  29. for action in self.available_actions:
  30. if action['action'] == action_name:
  31. action_callable = 'action_%s' % action_name
  32. return getattr(self, action_callable)
  33. else:
  34. raise ModerationError(_("Requested action is invalid."))
  35. def clean_selection(self, data):
  36. filtered_data = []
  37. for pk in data[:50]: # a tiny fail-safe to avoid too big workloads
  38. try:
  39. filtered_data.append(int(pk))
  40. except ValueError:
  41. pass
  42. if not filtered_data:
  43. raise ModerationError(self.select_threads_message)
  44. return filtered_data
  45. def handle_post(self, request, queryset):
  46. try:
  47. action, action_arg = self.resolve_action(request)
  48. self.selected_ids = self.clean_selection(
  49. request.POST.get_list('thread'))
  50. filtered_queryset = queryset.filter(pk__in=self.selected_ids)
  51. if filtered_queryset.exists():
  52. if action_arg:
  53. response = action(request, filtered_queryset, action_arg)
  54. else:
  55. response = action(request, filtered_queryset)
  56. if response:
  57. return response
  58. else:
  59. # prepare default response: page reload
  60. return redirect(request.path)
  61. else:
  62. raise ModerationError(self.select_threads_message)
  63. except ModerationError as e:
  64. messages.error(request, e.message)
  65. return False
  66. def get_list(self):
  67. return self.available_actions
  68. def get_selected_ids(self):
  69. return self.selected_ids
  70. class Sorting(object):
  71. sortings = (
  72. {
  73. 'method': 'recently-replied',
  74. 'name': ugettext_lazy("Recently replied"),
  75. 'order_by': '-last_post_on',
  76. },
  77. {
  78. 'method': 'last-replied',
  79. 'name': ugettext_lazy("Last replied"),
  80. 'order_by': 'last_post_on',
  81. },
  82. {
  83. 'method': 'most-replied',
  84. 'name': ugettext_lazy("Most replied"),
  85. 'order_by': '-replies',
  86. },
  87. {
  88. 'method': 'least-replied',
  89. 'name': ugettext_lazy("Least replied"),
  90. 'order_by': 'replies',
  91. },
  92. {
  93. 'method': 'newest',
  94. 'name': ugettext_lazy("Newest"),
  95. 'order_by': '-id',
  96. },
  97. {
  98. 'method': 'oldest',
  99. 'name': ugettext_lazy("Oldest"),
  100. 'order_by': 'id',
  101. },
  102. )
  103. def __init__(self, link_name, link_params):
  104. self.link_name = link_name
  105. self.link_params = link_params.copy()
  106. self.default_method = self.sortings[0]['method']
  107. def clean_kwargs(self, kwargs):
  108. sorting = kwargs.get('sort')
  109. if sorting:
  110. if sorting == self.default_method:
  111. kwargs.pop('sort')
  112. return kwargs
  113. available_sortings = [method['method'] for method in self.sortings]
  114. if sorting not in available_sortings:
  115. kwargs.pop('sort')
  116. return kwargs
  117. else:
  118. sorting = self.default_method
  119. self.set_sorting(sorting)
  120. return kwargs
  121. def set_sorting(self, method):
  122. for sorting in self.sortings:
  123. if sorting['method'] == method:
  124. self.sorting = sorting
  125. break
  126. @property
  127. def name(self):
  128. return self.sorting['name']
  129. def choices(self):
  130. choices = []
  131. for sorting in self.sortings:
  132. if sorting['method'] != self.sorting['method']:
  133. if sorting['method'] == self.default_method:
  134. self.link_params.pop('sort', None)
  135. else:
  136. self.link_params['sort'] = sorting['method']
  137. url = reverse(self.link_name, kwargs=self.link_params)
  138. choices.append({
  139. 'name': sorting['name'],
  140. 'url': url,
  141. })
  142. return choices
  143. def sort(self, threads):
  144. threads.sort(self.sorting['order_by'])
  145. class Threads(object):
  146. def __init__(self, user):
  147. self.user = user
  148. def sort(self, sort_by):
  149. self.queryset = self.queryset.order_by(sort_by)
  150. def label_threads(self, threads, labels=None):
  151. if labels:
  152. labels_dict = dict([(label.pk, label) for label in labels])
  153. else:
  154. labels_dict = Label.objects.get_cached_labels_dict()
  155. for thread in threads:
  156. thread.label = labels_dict.get(thread.label_id)
  157. def make_threads_read_aware(self, threads):
  158. threadstracker.make_read_aware(self.user, threads)
  159. class ThreadsView(ViewBase):
  160. def get_threads(self, request, kwargs):
  161. queryset = self.get_threads_queryset(request, forum)
  162. queryset = threads_qs.order_by('-last_post_id')
  163. page = paginate(threads_qs, kwargs.get('page', 0), 30, 10)
  164. threads = [thread for thread in page.object_list]
  165. return page, threads
  166. def get_threads_queryset(self, request):
  167. return forum.thread_set.all().order_by('-last_post_id')
  168. def clean_kwargs(self, request, kwargs):
  169. cleaned_kwargs = kwargs.copy()
  170. if request.user.is_anonymous():
  171. """we don't allow sort/filter for guests"""
  172. cleaned_kwargs.pop('sort', None)
  173. cleaned_kwargs.pop('show', None)
  174. return cleaned_kwargs