avatar.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import json
  2. from django.core.exceptions import PermissionDenied, ValidationError
  3. from django.utils.translation import ugettext as _
  4. from rest_framework import status
  5. from rest_framework.response import Response
  6. from misago.conf import settings
  7. from misago.core.utils import format_plaintext_for_html
  8. from ... import avatars
  9. from ...forms.moderation import ModerateAvatarForm
  10. def avatar_endpoint(request, pk=None):
  11. if request.user.is_avatar_locked:
  12. if request.user.avatar_lock_user_message:
  13. reason = format_plaintext_for_html(
  14. request.user.avatar_lock_user_message)
  15. else:
  16. reason = None
  17. return Response({
  18. 'detail': _("Your avatar is locked. You can't change it."),
  19. 'reason': reason
  20. }, status=status.HTTP_403_FORBIDDEN)
  21. avatar_options = get_avatar_options(request.user)
  22. if request.method == 'POST':
  23. return avatar_post(avatar_options, request.user, request.data)
  24. else:
  25. return Response(avatar_options)
  26. def get_avatar_options(user):
  27. options = {
  28. 'avatars': user.avatars,
  29. 'generated': True,
  30. 'gravatar': False,
  31. 'crop_src': False,
  32. 'crop_tmp': False,
  33. 'upload': False,
  34. 'galleries': False
  35. }
  36. # Allow existing galleries
  37. if avatars.gallery.galleries_exist():
  38. options['galleries'] = avatars.gallery.get_available_galleries()
  39. # Can't have custom avatar?
  40. if not settings.allow_custom_avatars:
  41. return options
  42. # Allow Gravatar download
  43. options['gravatar'] = True
  44. # Allow crop if we have uploaded temporary avatar
  45. if avatars.uploaded.has_source_avatar(user):
  46. try:
  47. options['crop_src'] = {
  48. 'url': user.avatar_src.url,
  49. 'crop': json.loads(user.avatar_crop),
  50. 'size': max(settings.MISAGO_AVATARS_SIZES)
  51. }
  52. except (TypeError, ValueError):
  53. pass
  54. # Allow crop of uploaded avatar
  55. if avatars.uploaded.has_temporary_avatar(user):
  56. options['crop_tmp'] = {
  57. 'url': user.avatar_tmp.url,
  58. 'size': max(settings.MISAGO_AVATARS_SIZES)
  59. }
  60. # Allow upload conditions
  61. options['upload'] = {
  62. 'limit': settings.avatar_upload_limit * 1024,
  63. 'allowed_extensions': avatars.uploaded.ALLOWED_EXTENSIONS,
  64. 'allowed_mime_types': avatars.uploaded.ALLOWED_MIME_TYPES,
  65. }
  66. return options
  67. class AvatarError(Exception):
  68. pass
  69. def avatar_post(options, user, data):
  70. try:
  71. type_options = options[data.get('avatar', 'nope')]
  72. if not type_options:
  73. return Response({
  74. 'detail': _("This avatar type is not allowed.")
  75. }, status=status.HTTP_400_BAD_REQUEST)
  76. rpc_handler = AVATAR_TYPES[data.get('avatar', 'nope')]
  77. except KeyError:
  78. return Response({
  79. 'detail': _("Unknown avatar type.")
  80. }, status=status.HTTP_400_BAD_REQUEST)
  81. try:
  82. response_dict = {'detail': rpc_handler(user, data)}
  83. except AvatarError as e:
  84. return Response({
  85. 'detail': e.args[0]
  86. }, status=status.HTTP_400_BAD_REQUEST)
  87. user.save()
  88. response_dict['avatars'] = user.avatars
  89. response_dict['options'] = get_avatar_options(user)
  90. return Response(response_dict)
  91. """
  92. Avatar rpc handlers
  93. """
  94. def avatar_generate(user, data):
  95. avatars.dynamic.set_avatar(user)
  96. return _("New avatar based on your account was set.")
  97. def avatar_gravatar(user, data):
  98. try:
  99. avatars.gravatar.set_avatar(user)
  100. return _("Gravatar was downloaded and set as new avatar.")
  101. except avatars.gravatar.GravatarError:
  102. raise AvatarError(_("Failed to connect to Gravatar servers."))
  103. except avatars.gravatar.NoGravatarAvailable:
  104. raise AvatarError(
  105. _("No Gravatar is associated with your e-mail address."))
  106. def avatar_gallery(user, data):
  107. image = data.get('image') or 'not-possible'
  108. if avatars.gallery.is_avatar_from_gallery(image):
  109. avatars.gallery.set_avatar(user, image)
  110. return _("Avatar from gallery was set.")
  111. else:
  112. raise AvatarError(_("Incorrect image."))
  113. def avatar_upload(user, data):
  114. new_avatar = data.get('image')
  115. if not new_avatar:
  116. raise AvatarError(_("No file was sent."))
  117. try:
  118. avatars.uploaded.handle_uploaded_file(user, new_avatar)
  119. except ValidationError as e:
  120. raise AvatarError(e.args[0])
  121. # send back url for temp image
  122. return user.avatar_tmp.url
  123. def avatar_crop_src(user, data):
  124. avatar_crop(user, data, 'src')
  125. return _("Avatar was re-cropped.")
  126. def avatar_crop_tmp(user, data):
  127. avatar_crop(user, data, 'tmp')
  128. return _("Uploaded avatar was set.")
  129. def avatar_crop(user, data, suffix):
  130. try:
  131. crop = avatars.uploaded.crop_source_image(
  132. user, suffix, data.get('crop', {}))
  133. user.avatar_crop = json.dumps(crop)
  134. except ValidationError as e:
  135. raise AvatarError(e.args[0])
  136. AVATAR_TYPES = {
  137. 'generated': avatar_generate,
  138. 'gravatar': avatar_gravatar,
  139. 'galleries': avatar_gallery,
  140. 'upload': avatar_upload,
  141. 'crop_src': avatar_crop_src,
  142. 'crop_tmp': avatar_crop_tmp,
  143. }
  144. def moderate_avatar_endpoint(request, profile):
  145. if request.method == "POST":
  146. is_avatar_locked = profile.is_avatar_locked
  147. form = ModerateAvatarForm(request.data, instance=profile)
  148. if form.is_valid():
  149. if form.cleaned_data['is_avatar_locked'] and not is_avatar_locked:
  150. avatars.dynamic.set_avatar(profile)
  151. form.save()
  152. return Response({
  153. 'avatars': profile.avatars,
  154. 'is_avatar_locked': int(profile.is_avatar_locked),
  155. 'avatar_lock_user_message': profile.avatar_lock_user_message,
  156. 'avatar_lock_staff_message': profile.avatar_lock_staff_message,
  157. })
  158. else:
  159. return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)
  160. else:
  161. return Response({
  162. 'is_avatar_locked': int(profile.is_avatar_locked),
  163. 'avatar_lock_user_message': profile.avatar_lock_user_message,
  164. 'avatar_lock_staff_message': profile.avatar_lock_staff_message,
  165. })