actions.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. from django.contrib import messages
  2. from django.db.transaction import atomic
  3. from django.shortcuts import render
  4. from django.utils import timezone
  5. from django.utils.translation import ugettext_lazy, ugettext as _, ungettext
  6. from misago.forums.lists import get_forum_path
  7. from misago.threads import moderation
  8. from misago.threads.forms.moderation import MergeThreadsForm, MoveThreadsForm
  9. from misago.threads.models import Thread
  10. from misago.threads.views.generic.threads import Actions
  11. __all__ = ['ForumActions']
  12. class ForumActions(Actions):
  13. def get_available_actions(self, kwargs):
  14. self.forum = kwargs['forum']
  15. actions = []
  16. if self.forum.acl['can_change_threads_labels'] == 2:
  17. for label in self.forum.labels:
  18. actions.append({
  19. 'action': 'label:%s' % label.slug,
  20. 'icon': 'tag',
  21. 'name': _('Label as "%(label)s"') % {'label': label.name}
  22. })
  23. if self.forum.labels:
  24. actions.append({
  25. 'action': 'unlabel',
  26. 'icon': 'times-circle',
  27. 'name': _("Remove labels")
  28. })
  29. if self.forum.acl['can_change_threads_weight'] == 2:
  30. actions.append({
  31. 'action': 'announce',
  32. 'icon': 'star',
  33. 'name': _("Change to announcements")
  34. })
  35. if self.forum.acl['can_change_threads_weight']:
  36. actions.append({
  37. 'action': 'pin',
  38. 'icon': 'bookmark',
  39. 'name': _("Change to pinned")
  40. })
  41. actions.append({
  42. 'action': 'reset',
  43. 'icon': 'circle',
  44. 'name': _("Reset weight")
  45. })
  46. if self.forum.acl['can_review_moderated_content']:
  47. actions.append({
  48. 'action': 'approve',
  49. 'icon': 'check',
  50. 'name': _("Approve threads")
  51. })
  52. if self.forum.acl['can_move_threads']:
  53. actions.append({
  54. 'action': 'move',
  55. 'icon': 'arrow-right',
  56. 'name': _("Move threads")
  57. })
  58. if self.forum.acl['can_merge_threads']:
  59. actions.append({
  60. 'action': 'merge',
  61. 'icon': 'reply-all',
  62. 'name': _("Merge threads")
  63. })
  64. if self.forum.acl['can_close_threads']:
  65. actions.append({
  66. 'action': 'open',
  67. 'icon': 'unlock-alt',
  68. 'name': _("Open threads")
  69. })
  70. actions.append({
  71. 'action': 'close',
  72. 'icon': 'lock',
  73. 'name': _("Close threads")
  74. })
  75. if self.forum.acl['can_hide_threads']:
  76. actions.append({
  77. 'action': 'unhide',
  78. 'icon': 'eye',
  79. 'name': _("Unhide threads")
  80. })
  81. actions.append({
  82. 'action': 'hide',
  83. 'icon': 'eye-slash',
  84. 'name': _("Hide threads")
  85. })
  86. if self.forum.acl['can_hide_threads'] == 2:
  87. actions.append({
  88. 'action': 'delete',
  89. 'icon': 'times',
  90. 'name': _("Delete threads"),
  91. 'confirmation': _("Are you sure you want to delete selected "
  92. "threads? This action can't be undone.")
  93. })
  94. return actions
  95. def action_label(self, request, threads, label_slug):
  96. for label in self.forum.labels:
  97. if label.slug == label_slug:
  98. break
  99. else:
  100. raise moderation.ModerationError(_("Requested action is invalid."))
  101. changed_threads = 0
  102. for thread in threads:
  103. if moderation.label_thread(request.user, thread, label):
  104. changed_threads += 1
  105. if changed_threads:
  106. message = ungettext(
  107. '%(changed)d thread was labeled "%(label)s".',
  108. '%(changed)d threads were labeled "%(label)s".',
  109. changed_threads)
  110. messages.success(request, message % {
  111. 'changed': changed_threads,
  112. 'label': label.name
  113. })
  114. else:
  115. message = _("No threads were labeled.")
  116. messages.info(request, message)
  117. def action_unlabel(self, request, threads):
  118. changed_threads = 0
  119. for thread in threads:
  120. if moderation.unlabel_thread(request.user, thread):
  121. changed_threads += 1
  122. if changed_threads:
  123. message = ungettext(
  124. '%(changed)d thread label was remoded.',
  125. '%(changed)d threads labels were removed.',
  126. changed_threads)
  127. messages.success(request, message % {'changed': changed_threads})
  128. else:
  129. message = _("No threads were unlabeled.")
  130. messages.info(request, message)
  131. def action_announce(self, request, threads):
  132. changed_threads = 0
  133. for thread in threads:
  134. if moderation.announce_thread(request.user, thread):
  135. changed_threads += 1
  136. if changed_threads:
  137. message = ungettext(
  138. '%(changed)d thread was changed to announcement.',
  139. '%(changed)d threads were changed to announcements.',
  140. changed_threads)
  141. messages.success(request, message % {'changed': changed_threads})
  142. else:
  143. message = _("No threads were changed to announcements.")
  144. messages.info(request, message)
  145. def action_pin(self, request, threads):
  146. changed_threads = 0
  147. for thread in threads:
  148. if moderation.pin_thread(request.user, thread):
  149. changed_threads += 1
  150. if changed_threads:
  151. message = ungettext(
  152. '%(changed)d thread was pinned.',
  153. '%(changed)d threads were pinned.',
  154. changed_threads)
  155. messages.success(request, message % {'changed': changed_threads})
  156. else:
  157. message = _("No threads were pinned.")
  158. messages.info(request, message)
  159. def action_reset(self, request, threads):
  160. changed_threads = 0
  161. for thread in threads:
  162. if moderation.reset_thread(request.user, thread):
  163. changed_threads += 1
  164. if changed_threads:
  165. message = ungettext(
  166. '%(changed)d thread weight was reset.',
  167. '%(changed)d threads weight was reset.',
  168. changed_threads)
  169. messages.success(request, message % {'changed': changed_threads})
  170. else:
  171. message = _("No threads weight was reset.")
  172. messages.info(request, message)
  173. move_threads_template = 'misago/threads/move.html'
  174. def action_move(self, request, threads):
  175. form = MoveThreadsForm(acl=request.user.acl, forum=self.forum)
  176. if request.method == "POST" and 'submit' in request.POST:
  177. form = MoveThreadsForm(
  178. request.POST, acl=request.user.acl, forum=self.forum)
  179. if form.is_valid():
  180. new_forum = form.cleaned_data['new_forum']
  181. for thread in threads:
  182. moderation.move_thread(request.user, thread, new_forum)
  183. with atomic():
  184. self.forum.synchronize()
  185. self.forum.save()
  186. new_forum.synchronize()
  187. new_forum.save()
  188. changed_threads = len(threads)
  189. message = ungettext(
  190. '%(changed)d thread was moved to %(forum)s.',
  191. '%(changed)d threads were moved to %(forum)s.',
  192. changed_threads)
  193. messages.success(request, message % {
  194. 'changed': changed_threads,
  195. 'forum': new_forum.name
  196. })
  197. return None # trigger threads list refresh
  198. return render(request, self.move_threads_template, {
  199. 'form': form,
  200. 'forum': self.forum,
  201. 'path': get_forum_path(self.forum),
  202. 'threads': threads
  203. })
  204. merge_threads_template = 'misago/threads/merge.html'
  205. def action_merge(self, request, threads):
  206. if len(threads) == 1:
  207. message = _("You have to select at least two threads to merge.")
  208. raise moderation.ModerationError(message)
  209. form = MergeThreadsForm()
  210. if request.method == "POST" and 'submit' in request.POST:
  211. form = MergeThreadsForm(request.POST)
  212. if form.is_valid():
  213. thread_title = form.cleaned_data['merged_thread_title']
  214. with atomic():
  215. merged_thread = Thread()
  216. merged_thread.weight = max(t.weight for t in threads)
  217. merged_thread.forum = self.forum
  218. merged_thread.set_title(
  219. form.cleaned_data['merged_thread_title'])
  220. merged_thread.starter_name = "-"
  221. merged_thread.starter_slug = "-"
  222. merged_thread.last_poster_name = "-"
  223. merged_thread.last_poster_slug = "-"
  224. merged_thread.started_on = timezone.now()
  225. merged_thread.last_post_on = timezone.now()
  226. merged_thread.save()
  227. for thread in threads:
  228. moderation.merge_thread(
  229. request.user, merged_thread, thread)
  230. with atomic():
  231. self.forum.synchronize()
  232. self.forum.save()
  233. changed_threads = len(threads)
  234. message = ungettext(
  235. '%(changed)d thread was merged into %(thread)s.',
  236. '%(changed)d threads were merged into %(thread)s.',
  237. changed_threads)
  238. messages.success(request, message % {
  239. 'changed': changed_threads,
  240. 'thread': merged_thread.title
  241. })
  242. return None # trigger threads list refresh
  243. return render(request, self.merge_threads_template, {
  244. 'form': form,
  245. 'forum': self.forum,
  246. 'path': get_forum_path(self.forum),
  247. 'threads': threads
  248. })
  249. def action_close(self, request, threads):
  250. changed_threads = 0
  251. for thread in threads:
  252. if moderation.close_thread(request.user, thread):
  253. changed_threads += 1
  254. if changed_threads:
  255. message = ungettext(
  256. '%(changed)d thread was closed.',
  257. '%(changed)d threads were closed.',
  258. changed_threads)
  259. messages.success(request, message % {'changed': changed_threads})
  260. else:
  261. message = _("No threads were closed.")
  262. messages.info(request, message)
  263. def action_open(self, request, threads):
  264. changed_threads = 0
  265. for thread in threads:
  266. if moderation.open_thread(request.user, thread):
  267. changed_threads += 1
  268. if changed_threads:
  269. message = ungettext(
  270. '%(changed)d thread was opened.',
  271. '%(changed)d threads were opened.',
  272. changed_threads)
  273. messages.success(request, message % {'changed': changed_threads})
  274. else:
  275. message = _("No threads were opened.")
  276. messages.info(request, message)
  277. def action_unhide(self, request, threads):
  278. changed_threads = 0
  279. for thread in threads:
  280. if moderation.unhide_thread(request.user, thread):
  281. changed_threads += 1
  282. if changed_threads:
  283. with atomic():
  284. self.forum.synchronize()
  285. self.forum.save()
  286. message = ungettext(
  287. '%(changed)d thread was made visible.',
  288. '%(changed)d threads were made visible.',
  289. changed_threads)
  290. messages.success(request, message % {'changed': changed_threads})
  291. else:
  292. message = _("No threads were made visible.")
  293. messages.info(request, message)
  294. def action_hide(self, request, threads):
  295. changed_threads = 0
  296. for thread in threads:
  297. if moderation.hide_thread(request.user, thread):
  298. changed_threads += 1
  299. if changed_threads:
  300. with atomic():
  301. self.forum.synchronize()
  302. self.forum.save()
  303. message = ungettext(
  304. '%(changed)d thread was hidden.',
  305. '%(changed)d threads were hidden.',
  306. changed_threads)
  307. messages.success(request, message % {'changed': changed_threads})
  308. else:
  309. message = _("No threads were hidden.")
  310. messages.info(request, message)
  311. def action_delete(self, request, threads):
  312. changed_threads = 0
  313. for thread in threads:
  314. if moderation.delete_thread(request.user, thread):
  315. changed_threads += 1
  316. if changed_threads:
  317. with atomic():
  318. self.forum.synchronize()
  319. self.forum.save()
  320. message = ungettext(
  321. '%(changed)d thread was deleted.',
  322. '%(changed)d threads were deleted.',
  323. changed_threads)
  324. messages.success(request, message % {'changed': changed_threads})
  325. else:
  326. message = _("No threads were deleted.")
  327. messages.info(request, message)