moderation.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 = _("%(username)s has maximum warning "
  58. "level and can't be warned.")
  59. message = message % {'username': 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 = _("%(username)s has been warned.")
  68. message = message % {'username': 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 = _("%(username)s's warning has been canceled.")
  104. message = message % {'username': 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 = _("%(username)s's warning has been deleted.")
  111. message = message % {'username': user.username}
  112. messages.success(request, message)
  113. @user_moderation_view(allow_rename_user)
  114. def rename(request, user):
  115. form = ChangeUsernameForm(user=user)
  116. if request.method == 'POST':
  117. old_username = user.username
  118. form = ChangeUsernameForm(request.POST, user=user)
  119. if form.is_valid():
  120. try:
  121. form.change_username(changed_by=user)
  122. message = _("%(old_username)s's username has been changed.")
  123. message = message % {'old_username': old_username}
  124. messages.success(request, message)
  125. return redirect(user_profile.get_default_link(),
  126. user_slug=user.slug, user_id=user.pk)
  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})
  132. @user_moderation_view(allow_moderate_avatar)
  133. def moderate_avatar(request, user):
  134. avatar_locked = user.is_avatar_locked
  135. form = ModerateAvatarForm(instance=user)
  136. if request.method == 'POST':
  137. form = ModerateAvatarForm(request.POST, instance=user)
  138. if form.is_valid():
  139. if not avatar_locked and form.cleaned_data['is_avatar_locked']:
  140. set_dynamic_avatar(user)
  141. user.save(update_fields=(
  142. 'is_avatar_locked',
  143. 'avatar_lock_user_message',
  144. 'avatar_lock_staff_message'
  145. ))
  146. message = _("%(username)s's avatar has been moderated.")
  147. message = message % {'username': user.username}
  148. messages.success(request, message)
  149. if 'stay' not in request.POST:
  150. return redirect(user_profile.get_default_link(),
  151. user_slug=user.slug, user_id=user.pk)
  152. return render(request, 'misago/modusers/avatar.html',
  153. {'profile': user, 'form': form})
  154. @user_moderation_view(allow_moderate_signature)
  155. def moderate_signature(request, user):
  156. form = ModerateSignatureForm(instance=user)
  157. if request.method == 'POST':
  158. form = ModerateSignatureForm(request.POST, instance=user)
  159. if form.is_valid():
  160. set_user_signature(user, form.cleaned_data['signature'])
  161. user.save(update_fields=(
  162. 'signature',
  163. 'signature_parsed',
  164. 'signature_checksum',
  165. 'is_signature_locked',
  166. 'signature_lock_user_message',
  167. 'signature_lock_staff_message'
  168. ))
  169. message = _("%(username)s's signature has been moderated.")
  170. message = message % {'username': user.username}
  171. messages.success(request, message)
  172. if 'stay' not in request.POST:
  173. return redirect(user_profile.get_default_link(),
  174. user_slug=user.slug, user_id=user.pk)
  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, 'form': form, 'editor': editor})
  182. @user_moderation_view(allow_ban_user)
  183. def ban_user(request, user):
  184. form = BanForm(user=user)
  185. if request.method == 'POST':
  186. form = BanForm(request.POST, user=user)
  187. if form.is_valid():
  188. form.ban_user()
  189. message = _("%(username)s has been banned.")
  190. messages.success(request, message % {'username': user.username})
  191. return redirect(user_profile.get_default_link(),
  192. user_slug=user.slug, user_id=user.pk)
  193. return render(request, 'misago/modusers/ban.html',
  194. {'profile': user, 'form': form})
  195. @require_POST
  196. @user_moderation_view(allow_lift_ban)
  197. def lift_user_ban(request, user):
  198. user_ban = get_user_ban(user).ban
  199. user_ban.lift()
  200. user_ban.save()
  201. Ban.objects.invalidate_cache()
  202. message = _("%(username)s's ban has been lifted.")
  203. messages.success(request, message % {'username': user.username})
  204. return redirect(user_profile.get_default_link(),
  205. user_slug=user.slug, user_id=user.pk)
  206. @require_POST
  207. @user_moderation_view(allow_delete_user)
  208. def delete(request, user):
  209. user.delete(delete_content=True)
  210. message = _("User %(username)s has been deleted.")
  211. messages.success(request, message % {'username': user.username})
  212. return redirect('misago:index')