avatar.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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 misago.users import avatars
  9. def avatar_endpoint(request, pk=None):
  10. if request.user.is_avatar_locked:
  11. if request.user.avatar_lock_user_message:
  12. reason = format_plaintext_for_html(
  13. request.user.avatar_lock_user_message)
  14. else:
  15. reason = None
  16. return Response({
  17. 'detail': _("Your avatar is locked. You can't change it."),
  18. 'reason': reason
  19. },
  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. 'generated': True,
  29. 'gravatar': False,
  30. 'crop_org': False,
  31. 'crop_tmp': False,
  32. 'upload': False,
  33. 'galleries': False
  34. }
  35. # Allow existing galleries
  36. if avatars.gallery.galleries_exist():
  37. options['galleries'] = avatars.gallery.get_available_galleries()
  38. # Can't have custom avatar?
  39. if not settings.allow_custom_avatars:
  40. return options
  41. # Allow Gravatar download
  42. options['gravatar'] = True
  43. # Allow crop with token if we have uploaded avatar
  44. if avatars.uploaded.has_original_avatar(user):
  45. try:
  46. options['crop_org'] = {
  47. 'token': avatars.get_avatar_hash(user, 'org'),
  48. 'crop': json.loads(user.avatar_crop),
  49. 'size': max(settings.MISAGO_AVATARS_SIZES)
  50. }
  51. except (TypeError, ValueError):
  52. pass
  53. # Allow crop of uploaded avatar
  54. if avatars.uploaded.has_temporary_avatar(user):
  55. options['crop_tmp'] = {
  56. 'size': max(settings.MISAGO_AVATARS_SIZES)
  57. }
  58. # Allow upload conditions
  59. options['upload'] = {
  60. 'limit': settings.avatar_upload_limit * 1000,
  61. 'allowed_extensions': avatars.uploaded.ALLOWED_EXTENSIONS,
  62. 'allowed_mime_types': avatars.uploaded.ALLOWED_MIME_TYPES,
  63. }
  64. return options
  65. class AvatarError(Exception):
  66. pass
  67. def avatar_post(options, user, data):
  68. try:
  69. type_options = options[data.get('avatar', 'nope')]
  70. if not type_options:
  71. return Response({'detail': _("This avatar type is not allowed.")},
  72. status=status.HTTP_400_BAD_REQUEST)
  73. rpc_handler = AVATAR_TYPES[data.get('avatar', 'nope')]
  74. except KeyError:
  75. return Response({'detail': _("Unknown avatar type.")},
  76. status=status.HTTP_400_BAD_REQUEST)
  77. try:
  78. response_dict = {'detail': rpc_handler(user, data)}
  79. except AvatarError as e:
  80. return Response({'detail': e.args[0]},
  81. status=status.HTTP_400_BAD_REQUEST)
  82. user.avatar_hash = avatars.get_avatar_hash(user)
  83. user.save(update_fields=['avatar_hash', 'avatar_crop'])
  84. response_dict['avatar_hash'] = user.avatar_hash
  85. response_dict['options'] = get_avatar_options(user)
  86. return Response(response_dict)
  87. """
  88. Avatar rpc handlers
  89. """
  90. def avatar_generate(user, data):
  91. avatars.dynamic.set_avatar(user)
  92. return _("New avatar based on your account was set.")
  93. def avatar_gravatar(user, data):
  94. try:
  95. avatars.gravatar.set_avatar(user)
  96. return _("Gravatar was downloaded and set as new avatar.")
  97. except avatars.gravatar.GravatarError:
  98. raise AvatarError(_("Failed to connect to Gravatar servers."))
  99. except avatars.gravatar.NoGravatarAvailable:
  100. raise AvatarError(
  101. _("No Gravatar is associated with your e-mail address."))
  102. def avatar_gallery(user, data):
  103. image = data.get('image') or 'not-possible'
  104. if avatars.gallery.is_avatar_from_gallery(image):
  105. avatars.gallery.set_avatar(user, image)
  106. return _("Avatar from gallery was set.")
  107. else:
  108. raise AvatarError(_("Incorrect image."))
  109. def avatar_upload(user, data):
  110. new_avatar = data.get('image')
  111. if not new_avatar:
  112. raise AvatarError(_("No file was sent."))
  113. try:
  114. avatars.uploaded.handle_uploaded_file(user, new_avatar)
  115. except ValidationError as e:
  116. raise AvatarError(e.args[0])
  117. # send back token for temp image
  118. return avatars.get_avatar_hash(user, 'tmp')
  119. def avatar_crop_org(user, data):
  120. avatar_crop(user, data, 'org')
  121. return _("Avatar was re-cropped.")
  122. def avatar_crop_tmp(user, data):
  123. avatar_crop(user, data, 'tmp')
  124. return _("Uploaded avatar was set.")
  125. def avatar_crop(user, data, suffix):
  126. try:
  127. crop = avatars.uploaded.crop_source_image(
  128. user, suffix, data.get('crop', {}))
  129. user.avatar_crop = json.dumps(crop)
  130. except ValidationError as e:
  131. raise AvatarError(e.args[0])
  132. AVATAR_TYPES = {
  133. 'generated': avatar_generate,
  134. 'gravatar': avatar_gravatar,
  135. 'galleries': avatar_gallery,
  136. 'upload': avatar_upload,
  137. 'crop_org': avatar_crop_org,
  138. 'crop_tmp': avatar_crop_tmp,
  139. }