usercp.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. from django.contrib import messages
  2. from django.contrib.auth import update_session_auth_hash
  3. from django.db import IntegrityError, transaction
  4. from django.http import Http404, JsonResponse
  5. from django.shortcuts import redirect, render as django_render
  6. from django.utils.translation import ugettext as _
  7. from django.views.decorators.debug import sensitive_post_parameters
  8. from misago.conf import settings
  9. from misago.core.decorators import ajax_only, require_POST
  10. from misago.core.exceptions import AjaxError
  11. from misago.core.mail import mail_user
  12. from misago.markup import Editor
  13. from misago.users import avatars
  14. from misago.users.decorators import deny_guests
  15. from misago.users.forms.usercp import (ChangeForumOptionsForm,
  16. EditSignatureForm,
  17. ChangeUsernameForm,
  18. ChangeEmailPasswordForm)
  19. from misago.users.signatures import set_user_signature
  20. from misago.users.sites import usercp
  21. from misago.users.changedcredentials import (cache_new_credentials,
  22. get_new_credentials)
  23. from misago.users.namechanges import UsernameChanges
  24. def render(request, template, context=None):
  25. context = context or {}
  26. context['pages'] = usercp.get_pages(request)
  27. for page in context['pages']:
  28. if page['is_active']:
  29. context['active_page'] = page
  30. break
  31. return django_render(request, template, context)
  32. @deny_guests
  33. def change_forum_options(request):
  34. form = ChangeForumOptionsForm(instance=request.user)
  35. if request.method == 'POST':
  36. form = ChangeForumOptionsForm(request.POST, instance=request.user)
  37. if form.is_valid():
  38. form.save()
  39. message = _("Your forum options have been changed.")
  40. messages.success(request, message)
  41. return redirect('misago:usercp_change_forum_options')
  42. return render(request, 'misago/usercp/change_forum_options.html',
  43. {'form': form})
  44. @deny_guests
  45. def change_avatar(request):
  46. avatar_size = max(settings.MISAGO_AVATARS_SIZES)
  47. if not request.user.is_avatar_banned and request.method == 'POST':
  48. if 'dl-gravatar' in request.POST and settings.allow_custom_avatars:
  49. try:
  50. avatars.gravatar.set_avatar(request.user)
  51. message = _("Gravatar was downloaded and set as new avatar.")
  52. messages.success(request, message)
  53. except avatars.gravatar.GravatarError:
  54. message = _("Failed to connect to Gravatar servers.")
  55. messages.info(request, message)
  56. except avatars.gravatar.NoGravatarAvailable:
  57. message = _("No Gravatar is associated "
  58. "with your e-mail address.")
  59. messages.info(request, message)
  60. elif 'set-dynamic' in request.POST:
  61. avatars.dynamic.set_avatar(request.user)
  62. message = _("New avatar based on your account was set.")
  63. messages.success(request, message)
  64. return redirect('misago:usercp_change_avatar')
  65. return render(request, 'misago/usercp/change_avatar.html', {
  66. 'avatar_size': avatar_size,
  67. 'galleries_exist': avatars.gallery.galleries_exist()
  68. })
  69. def avatar_not_banned(f):
  70. def decorator(request, *args, **kwargs):
  71. if request.user.is_avatar_banned:
  72. message = _("You don't have permission to change your avatar.")
  73. messages.info(request, message)
  74. return redirect('misago:usercp_change_avatar')
  75. else:
  76. return f(request, *args, **kwargs)
  77. return decorator
  78. @deny_guests
  79. @avatar_not_banned
  80. def upload_avatar(request):
  81. if not settings.allow_custom_avatars:
  82. messages.info(request, _("Avatar uploads are currently disabled."))
  83. return redirect('misago:usercp_change_avatar')
  84. upload_limit = settings.avatar_upload_limit * 1024
  85. return render(request, 'misago/usercp/upload_avatar.html', {
  86. 'upload_limit': upload_limit,
  87. })
  88. @ajax_only
  89. @deny_guests
  90. @require_POST
  91. @avatar_not_banned
  92. def upload_avatar_handler(request):
  93. if not settings.allow_custom_avatars:
  94. raise AjaxError(_("Avatar uploads are currently disabled."))
  95. new_avatar = request.FILES.get('new-avatar');
  96. if not new_avatar:
  97. raise AjaxError(_("No file was sent."))
  98. raise AjaxError(_("Not yet completed!"))
  99. @deny_guests
  100. @avatar_not_banned
  101. def crop_avatar(request, crop_uploaded_avatar=True):
  102. return render(request, 'misago/usercp/crop_avatar.html', {})
  103. @deny_guests
  104. @avatar_not_banned
  105. def avatar_galleries(request):
  106. if not avatars.gallery.galleries_exist():
  107. messages.info(request, _("No avatars galleries exist."))
  108. return redirect('misago:usercp_change_avatar')
  109. if request.method == 'POST':
  110. new_image = request.POST.get('new-image')
  111. if new_image:
  112. if avatars.gallery.is_avatar_from_gallery(new_image):
  113. avatars.gallery.set_avatar(request.user, new_image)
  114. messages.success(request, _("Avatar from gallery was set."))
  115. return redirect('misago:usercp_change_avatar')
  116. else:
  117. messages.error(request, _("Incorrect image."))
  118. return render(request, 'misago/usercp/avatar_galleries.html', {
  119. 'galleries': avatars.gallery.get_available_galleries()
  120. })
  121. @deny_guests
  122. def edit_signature(request):
  123. if not request.user.acl['can_have_signature']:
  124. raise Http404()
  125. form = EditSignatureForm(instance=request.user)
  126. if not request.user.is_signature_banned and request.method == 'POST':
  127. form = EditSignatureForm(request.POST, instance=request.user)
  128. if form.is_valid():
  129. set_user_signature(request.user, form.cleaned_data['signature'])
  130. request.user.save(update_fields=['signature', 'signature_parsed',
  131. 'signature_checksum'])
  132. if form.cleaned_data['signature']:
  133. messages.success(request, _("Your signature has been edited."))
  134. else:
  135. message = _("Your signature has been cleared.")
  136. messages.success(request, message)
  137. return redirect('misago:usercp_edit_signature')
  138. acl = request.user.acl
  139. editor = Editor(form['signature'],
  140. allow_blocks=acl['allow_signature_blocks'],
  141. allow_links=acl['allow_signature_links'],
  142. allow_images=acl['allow_signature_images'])
  143. return render(request, 'misago/usercp/edit_signature.html',
  144. {'form': form, 'editor': editor})
  145. @deny_guests
  146. @transaction.atomic()
  147. def change_username(request):
  148. namechanges = UsernameChanges(request.user)
  149. form = ChangeUsernameForm()
  150. if request.method == 'POST' and namechanges.left:
  151. form = ChangeUsernameForm(request.POST, user=request.user)
  152. if form.is_valid():
  153. request.user.set_username(form.cleaned_data['new_username'])
  154. request.user.save(update_fields=['username', 'username_slug'])
  155. message = _("Your username has been changed.")
  156. messages.success(request, message)
  157. return redirect('misago:usercp_change_username')
  158. return render(request, 'misago/usercp/change_username.html', {
  159. 'form': form,
  160. 'changes_left': namechanges.left,
  161. 'next_change_on': namechanges.next_on
  162. })
  163. @sensitive_post_parameters()
  164. @deny_guests
  165. def change_email_password(request):
  166. form = ChangeEmailPasswordForm()
  167. if request.method == 'POST':
  168. form = ChangeEmailPasswordForm(request.POST, user=request.user)
  169. if form.is_valid():
  170. new_email = ''
  171. new_password = ''
  172. # Store original data
  173. old_email = request.user.email
  174. old_password = request.user.password
  175. # Assign new creds to user temporarily
  176. if form.cleaned_data['new_email']:
  177. request.user.set_email(form.cleaned_data['new_email'])
  178. new_email = request.user.email
  179. if form.cleaned_data['new_password']:
  180. request.user.set_password(form.cleaned_data['new_password'])
  181. new_password = request.user.password
  182. request.user.email = old_email
  183. request.user.password = old_password
  184. credentials_token = cache_new_credentials(
  185. request.user, new_email, new_password)
  186. mail_subject = _("Confirm changes to %(username)s account "
  187. "on %(forum_title)s forums")
  188. subject_formats = {'username': request.user.username,
  189. 'forum_title': settings.forum_name}
  190. mail_subject = mail_subject % subject_formats
  191. if new_email:
  192. # finally override email before sending message
  193. request.user.email = new_email
  194. mail_user(request, request.user, mail_subject,
  195. 'misago/emails/change_email_password',
  196. {'credentials_token': credentials_token})
  197. message = _("E-mail was sent to %(email)s with a link that "
  198. "you have to click to confirm changes.")
  199. messages.info(request, message % {'email': request.user.email})
  200. return redirect('misago:usercp_change_email_password')
  201. return render(request, 'misago/usercp/change_email_password.html',
  202. {'form': form})
  203. @deny_guests
  204. def confirm_email_password_change(request, token):
  205. new_credentials = get_new_credentials(request.user, token)
  206. if not new_credentials:
  207. messages.error(request, _("Confirmation link is invalid."))
  208. else:
  209. changes_made = []
  210. if new_credentials['email']:
  211. request.user.set_email(new_credentials['email'])
  212. changes_made.extend(['email', 'email_hash'])
  213. if new_credentials['password']:
  214. request.user.password = new_credentials['password']
  215. update_session_auth_hash(request, request.user)
  216. changes_made.append('password')
  217. try:
  218. request.user.save(update_fields=changes_made)
  219. message = _("Changes in e-mail and password have been saved.")
  220. messages.success(request, message)
  221. except IntegrityError:
  222. messages.error(request, _("Confirmation link is invalid."))
  223. return redirect('misago:usercp_change_email_password')