actions.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from django.contrib import messages
  2. from django.shortcuts import redirect
  3. from django.utils.translation import ugettext_lazy as _
  4. from misago.core.exceptions import AjaxError
  5. from misago.threads.moderation import ModerationError
  6. __all__ = ['ActionsBase', 'ReloadAfterDelete']
  7. class ReloadAfterDelete(object):
  8. pass
  9. class ActionsBase(object):
  10. query_key = 'action'
  11. invalid_action_message = _("Requested action is invalid.")
  12. def __init__(self, **kwargs):
  13. if kwargs.get('user').is_authenticated():
  14. self.available_actions = self.get_available_actions(kwargs)
  15. else:
  16. self.available_actions = []
  17. self.selected_ids = []
  18. def __nonzero__(self):
  19. return bool(self.available_actions)
  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.POST.get(self.query_key)
  25. for action in self.available_actions:
  26. if action['action'] == action_name:
  27. if ':' in action_name:
  28. action_bits = action_name.split(':')
  29. action_name = action_bits[0]
  30. action_arg = action_bits[1]
  31. else:
  32. action_arg = None
  33. action_callable = 'action_%s' % action_name
  34. return getattr(self, action_callable), action_arg
  35. else:
  36. raise ModerationError(self.invalid_action_message)
  37. def clean_selection(self, data):
  38. filtered_data = []
  39. for pk in data[:50]: # a tiny fail-safe to avoid too big workloads
  40. try:
  41. filtered_data.append(int(pk))
  42. except ValueError:
  43. pass
  44. if not filtered_data:
  45. raise ModerationError(self.select_items_message)
  46. return filtered_data
  47. def handle_post(self, request, target):
  48. try:
  49. if self.is_mass_action:
  50. return self.handle_mass_action(request, target)
  51. else:
  52. return self.handle_single_action(request, target)
  53. except ModerationError as e:
  54. if request.is_ajax():
  55. raise AjaxError(e.message, 406)
  56. else:
  57. messages.error(request, e.message)
  58. return False
  59. def handle_mass_action(self, request, queryset):
  60. action, action_arg = self.resolve_action(request)
  61. self.selected_ids = self.clean_selection(
  62. request.POST.getlist('item', []))
  63. filtered_queryset = queryset.filter(pk__in=self.selected_ids)
  64. if filtered_queryset.exists():
  65. if action_arg:
  66. response = action(request, filtered_queryset, action_arg)
  67. else:
  68. response = action(request, filtered_queryset)
  69. if isinstance(response, ReloadAfterDelete):
  70. return self.redirect_after_deletion(request, queryset)
  71. if response:
  72. return response
  73. elif request.is_ajax():
  74. raise AjaxError(self.invalid_action_message, 406)
  75. else:
  76. # prepare default response: page reload
  77. return redirect(request.path)
  78. else:
  79. raise ModerationError(self.select_items_message)
  80. def redirect_after_deletion(self, request, queryset):
  81. raise NotImplementedError("action handlers should declare their own "
  82. "redirect_after_deletion methods")
  83. def handle_single_action(self, request, target):
  84. action, action_arg = self.resolve_action(request)
  85. if action_arg:
  86. response = action(request, target, action_arg)
  87. else:
  88. response = action(request, target)
  89. if response:
  90. return response
  91. elif request.is_ajax():
  92. raise AjaxError(self.invalid_action_message, 406)
  93. else:
  94. # prepare default response: page reload
  95. return redirect(request.path)
  96. def get_list(self):
  97. return self.available_actions
  98. def get_selected_ids(self):
  99. return self.selected_ids