moderation.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. from django.core.urlresolvers import reverse
  2. from django.contrib import messages
  3. from django.contrib.auth import get_user_model
  4. from django.db import IntegrityError, transaction
  5. from django.shortcuts import redirect, render
  6. from django.utils.translation import ugettext as _
  7. from misago.acl import add_acl
  8. from misago.core.decorators import require_POST
  9. from misago.core.shortcuts import get_object_or_404, validate_slug
  10. from misago.core.utils import clean_return_path
  11. from misago.markup import Editor
  12. from misago.users.avatars.dynamic import set_avatar as set_dynamic_avatar
  13. from misago.users import warnings
  14. from misago.users.bans import get_user_ban
  15. from misago.users.decorators import deny_guests
  16. from misago.users.forms.rename import ChangeUsernameForm
  17. from misago.users.forms.modusers import (BanForm, ModerateAvatarForm,
  18. ModerateSignatureForm, WarnUserForm)
  19. from misago.users.models import Ban
  20. from misago.users.permissions.moderation import (allow_rename_user,
  21. allow_moderate_avatar,
  22. allow_moderate_signature,
  23. allow_ban_user,
  24. allow_lift_ban)
  25. from misago.users.permissions.warnings import (allow_warn_user,
  26. allow_see_warnings,
  27. allow_cancel_warning,
  28. allow_delete_warning)
  29. from misago.users.permissions.delete import allow_delete_user
  30. from misago.users.signatures import set_user_signature
  31. from misago.users.sites import user_profile
  32. def user_moderation_view(required_permission=None):
  33. def wrap(f):
  34. @deny_guests
  35. @transaction.atomic
  36. def decorator(request, *args, **kwargs):
  37. queryset = get_user_model().objects.select_for_update()
  38. user_id = kwargs.pop('user_id')
  39. kwargs['user'] = get_object_or_404(queryset, id=user_id)
  40. validate_slug(kwargs['user'], kwargs.pop('user_slug'))
  41. add_acl(request.user, kwargs['user'])
  42. if required_permission:
  43. required_permission(request.user, kwargs['user'])
  44. return f(request, *args, **kwargs)
  45. return decorator
  46. return wrap
  47. def moderation_return_path(request, user):
  48. return_path = clean_return_path(request)
  49. if not return_path:
  50. return reverse(user_profile.get_default_link(),
  51. kwargs={'user_slug': user.slug, 'user_id': user.pk})
  52. return return_path
  53. @user_moderation_view(allow_warn_user)
  54. def warn(request, user, reason=None):
  55. return_path = moderation_return_path(request, user)
  56. if warnings.is_user_warning_level_max(user):
  57. message = _("%(user)s has maximum warning "
  58. "level and can't be warned.")
  59. message = message % {'user': user.username}
  60. messages.info(request, message)
  61. return redirect(return_path)
  62. form = WarnUserForm(initial={'reason': reason})
  63. if request.method == 'POST':
  64. form = WarnUserForm(request.POST)
  65. if form.is_valid():
  66. warnings.warn_user(request.user, user, form.cleaned_data['reason'])
  67. message = _("%(user)s has been warned.")
  68. message = message % {'user': user.username}
  69. messages.success(request, message)
  70. return redirect(return_path)
  71. warning_levels = warnings.get_warning_levels()
  72. current_level = warning_levels[user.warning_level]
  73. next_level = warning_levels[user.warning_level + 1]
  74. return render(request, 'misago/modusers/warn.html', {
  75. 'profile': user,
  76. 'form': form,
  77. 'return_path': return_path,
  78. 'current_level': current_level,
  79. 'next_level': next_level
  80. })
  81. def warning_moderation_view(required_permission=None):
  82. def wrap(f):
  83. @deny_guests
  84. @transaction.atomic
  85. def decorator(request, *args, **kwargs):
  86. queryset = kwargs['user'].warnings
  87. warning_id = kwargs.pop('warning_id')
  88. kwargs['warning'] = get_object_or_404(queryset, id=warning_id)
  89. add_acl(request.user, kwargs['warning'])
  90. required_permission(request.user, kwargs['warning'])
  91. response = f(request, *args, **kwargs)
  92. if response:
  93. return response
  94. else:
  95. return_path = moderation_return_path(request, kwargs['user'])
  96. return redirect(return_path)
  97. return decorator
  98. return wrap
  99. @user_moderation_view(allow_see_warnings)
  100. @warning_moderation_view(allow_cancel_warning)
  101. def cancel_warning(request, user, warning):
  102. warnings.cancel_warning(request.user, user, warning)
  103. message = _("%(user)s's warning has been canceled.")
  104. message = message % {'user': user.username}
  105. messages.success(request, message)
  106. @user_moderation_view(allow_see_warnings)
  107. @warning_moderation_view(allow_delete_warning)
  108. def delete_warning(request, user, warning):
  109. warnings.delete_warning(request.user, user, warning)
  110. message = _("%(user)s's warning has been deleted.")
  111. message = message % {'user': user.username}
  112. messages.success(request, message)
  113. @user_moderation_view(allow_rename_user)
  114. def rename(request, user):
  115. return_path = moderation_return_path(request, user)
  116. form = ChangeUsernameForm(user=user)
  117. if request.method == 'POST':
  118. old_username = user.username
  119. form = ChangeUsernameForm(request.POST, user=user)
  120. if form.is_valid():
  121. try:
  122. form.change_username(changed_by=user)
  123. message = _("%(old_username)s's username has been changed.")
  124. message = message % {'old_username': old_username}
  125. messages.success(request, message)
  126. return redirect(return_path)
  127. except IntegrityError:
  128. message = _("Error changing username. Please try again.")
  129. messages.error(request, message)
  130. return render(request, 'misago/modusers/rename.html',
  131. {'profile': user, 'form': form, 'return_path': return_path})
  132. @user_moderation_view(allow_moderate_avatar)
  133. def moderate_avatar(request, user):
  134. return_path = moderation_return_path(request, user)
  135. avatar_locked = user.is_avatar_locked
  136. form = ModerateAvatarForm(instance=user)
  137. if request.method == 'POST':
  138. form = ModerateAvatarForm(request.POST, instance=user)
  139. if form.is_valid():
  140. if not avatar_locked and form.cleaned_data['is_avatar_locked']:
  141. set_dynamic_avatar(user)
  142. user.save(update_fields=(
  143. 'is_avatar_locked',
  144. 'avatar_lock_user_message',
  145. 'avatar_lock_staff_message'
  146. ))
  147. message = _("%(user)s's avatar has been moderated.")
  148. message = message % {'user': user.username}
  149. messages.success(request, message)
  150. if 'stay' not in request.POST:
  151. return redirect(return_path)
  152. return render(request, 'misago/modusers/avatar.html',
  153. {'profile': user, 'form': form, 'return_path': return_path})
  154. @user_moderation_view(allow_moderate_signature)
  155. def moderate_signature(request, user):
  156. return_path = moderation_return_path(request, user)
  157. form = ModerateSignatureForm(instance=user)
  158. if request.method == 'POST':
  159. form = ModerateSignatureForm(request.POST, instance=user)
  160. if form.is_valid():
  161. set_user_signature(user, form.cleaned_data['signature'])
  162. user.save(update_fields=(
  163. 'signature',
  164. 'signature_parsed',
  165. 'signature_checksum',
  166. 'is_signature_locked',
  167. 'signature_lock_user_message',
  168. 'signature_lock_staff_message'
  169. ))
  170. message = _("%(user)s's signature has been moderated.")
  171. message = message % {'user': user.username}
  172. messages.success(request, message)
  173. if 'stay' not in request.POST:
  174. return redirect(return_path)
  175. acl = user.acl
  176. editor = Editor(form['signature'],
  177. allow_blocks=acl['allow_signature_blocks'],
  178. allow_links=acl['allow_signature_links'],
  179. allow_images=acl['allow_signature_images'])
  180. return render(request, 'misago/modusers/signature.html', {
  181. 'profile': user,
  182. 'form': form,
  183. 'editor': editor,
  184. 'return_path': return_path
  185. })
  186. @user_moderation_view(allow_ban_user)
  187. def ban_user(request, user):
  188. return_path = moderation_return_path(request, user)
  189. form = BanForm(user=user)
  190. if request.method == 'POST':
  191. form = BanForm(request.POST, user=user)
  192. if form.is_valid():
  193. form.ban_user()
  194. message = _("%(user)s has been banned.")
  195. messages.success(request, message % {'user': user.username})
  196. return redirect(return_path)
  197. return render(request, 'misago/modusers/ban.html',
  198. {'profile': user, 'form': form, 'return_path': return_path})
  199. @require_POST
  200. @user_moderation_view(allow_lift_ban)
  201. def lift_user_ban(request, user):
  202. return_path = moderation_return_path(request, user)
  203. user_ban = get_user_ban(user).ban
  204. user_ban.lift()
  205. user_ban.save()
  206. Ban.objects.invalidate_cache()
  207. message = _("%(user)s's ban has been lifted.")
  208. messages.success(request, message % {'user': user.username})
  209. return redirect(return_path)
  210. @require_POST
  211. @user_moderation_view(allow_delete_user)
  212. def delete(request, user):
  213. user.delete(delete_content=True)
  214. message = _("User %(user)s has been deleted.")
  215. messages.success(request, message % {'user': user.username})
  216. return redirect('misago:index')