threads.py 7.4 KB

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