views.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. from path import path
  2. from PIL import Image
  3. from django.conf import settings
  4. from django.core.exceptions import ValidationError
  5. from django.core.urlresolvers import reverse
  6. from django.shortcuts import redirect
  7. from django.utils.encoding import smart_str
  8. from django.utils.translation import ugettext as _
  9. from misago.apps.errors import error404
  10. from misago.decorators import block_guest
  11. from misago.forms import FormLayout
  12. from misago.messages import Message
  13. from misago.utils.strings import random_string
  14. from misago.utils.avatars import resizeimage
  15. from misago.apps.usercp.template import RequestContext
  16. from misago.apps.usercp.avatar.forms import UploadAvatarForm
  17. def avatar_view(f):
  18. def decorator(*args, **kwargs):
  19. request = args[0]
  20. if request.user.avatar_ban:
  21. return request.theme.render_to_response('usercp/avatar_banned.html',
  22. context_instance=RequestContext(request, {
  23. 'tab': 'avatar',
  24. }));
  25. return f(*args, **kwargs)
  26. return decorator
  27. @block_guest
  28. @avatar_view
  29. def avatar(request):
  30. message = request.messages.get_message('usercp_avatar')
  31. return request.theme.render_to_response('usercp/avatar.html',
  32. context_instance=RequestContext(request, {
  33. 'message': message,
  34. 'tab': 'avatar',
  35. }));
  36. @block_guest
  37. @avatar_view
  38. def gravatar(request):
  39. if not 'gravatar' in request.settings.avatars_types:
  40. return error404(request)
  41. if request.user.avatar_type != 'gravatar':
  42. if request.csrf.request_secure(request):
  43. request.user.delete_avatar()
  44. request.user.avatar_type = 'gravatar'
  45. request.user.save(force_update=True)
  46. request.messages.set_flash(Message(_("Your avatar has been changed to Gravatar.")), 'success', 'usercp_avatar')
  47. else:
  48. request.messages.set_flash(Message(_("Request authorisation is invalid.")), 'error', 'usercp_avatar')
  49. return redirect(reverse('usercp_avatar'))
  50. @block_guest
  51. @avatar_view
  52. def gallery(request):
  53. if not 'gallery' in request.settings.avatars_types:
  54. return error404(request)
  55. allowed_avatars = []
  56. galleries = []
  57. for directory in path(settings.STATICFILES_DIRS[0]).joinpath('avatars').dirs():
  58. if directory[-7:] != '_locked' and directory[-8:] != '_default':
  59. gallery = {'name': directory[-7:], 'avatars': []}
  60. avatars = directory.files('*.gif')
  61. avatars += directory.files('*.jpg')
  62. avatars += directory.files('*.jpeg')
  63. avatars += directory.files('*.png')
  64. for item in avatars:
  65. gallery['avatars'].append('/'.join(path(item).splitall()[-2:]))
  66. galleries.append(gallery)
  67. allowed_avatars += gallery['avatars']
  68. if not allowed_avatars:
  69. request.messages.set_flash(Message(_("No avatars are avaiable.")), 'info', 'usercp_avatar')
  70. return redirect(reverse('usercp_avatar'))
  71. message = request.messages.get_message('usercp_avatar')
  72. if request.method == 'POST':
  73. if request.csrf.request_secure(request):
  74. new_avatar = request.POST.get('avatar_image')
  75. if new_avatar in allowed_avatars:
  76. request.user.delete_avatar()
  77. request.user.avatar_type = 'gallery'
  78. request.user.avatar_image = new_avatar
  79. request.user.save(force_update=True)
  80. request.messages.set_flash(Message(_("Your avatar has been changed to one from gallery.")), 'success', 'usercp_avatar')
  81. return redirect(reverse('usercp_avatar'))
  82. message = Message(_("Selected Avatar is incorrect."), 'error')
  83. else:
  84. message = Message(_("Request authorisation is invalid."), 'error')
  85. return request.theme.render_to_response('usercp/avatar_gallery.html',
  86. context_instance=RequestContext(request, {
  87. 'message': message,
  88. 'galleries': galleries,
  89. 'tab': 'avatar',
  90. }));
  91. @block_guest
  92. @avatar_view
  93. def upload(request):
  94. if not 'upload' in request.settings.avatars_types:
  95. return error404(request)
  96. message = request.messages.get_message('usercp_avatar')
  97. if request.method == 'POST':
  98. form = UploadAvatarForm(request.POST, request.FILES, request=request)
  99. if form.is_valid():
  100. request.user.delete_avatar_temp()
  101. image = form.cleaned_data['avatar_upload']
  102. image_name, image_extension = path(smart_str(image.name.lower())).splitext()
  103. image_name = '%s_tmp_%s%s' % (request.user.pk, random_string(8), image_extension)
  104. image_path = settings.MEDIA_ROOT + 'avatars/' + image_name
  105. request.user.avatar_temp = image_name
  106. with open(image_path, 'wb+') as destination:
  107. for chunk in image.chunks():
  108. destination.write(chunk)
  109. request.user.save()
  110. try:
  111. image = Image.open(image_path)
  112. if not image.format in ['GIF', 'PNG', 'JPEG']:
  113. raise ValidationError()
  114. image.seek(0)
  115. image.save(image_path)
  116. if request.POST.get('js_check'):
  117. return redirect(reverse('usercp_avatar_upload_crop'))
  118. # Redirect to crop page didnt happen, handle avatar with old school hollywood way
  119. image_path = settings.MEDIA_ROOT + 'avatars/'
  120. source = Image.open(image_path + request.user.avatar_temp)
  121. image_name, image_extension = path(request.user.avatar_temp).splitext()
  122. image_name = '%s_%s%s' % (request.user.pk, random_string(8), image_extension)
  123. resizeimage(source, settings.AVATAR_SIZES[0], image_path + image_name, info=source.info, format=source.format)
  124. for size in settings.AVATAR_SIZES[1:]:
  125. resizeimage(source, size, image_path + str(size) + '_' + image_name, info=source.info, format=source.format)
  126. # Update user model one more time
  127. request.user.delete_avatar_image()
  128. request.user.delete_avatar_original()
  129. request.user.avatar_type = 'upload'
  130. request.user.avatar_original = '%s_org_%s%s' % (request.user.pk, random_string(8), image_extension)
  131. source.save(image_path + request.user.avatar_original)
  132. request.user.delete_avatar_temp()
  133. request.user.avatar_image = image_name
  134. request.user.save(force_update=True)
  135. # Set message and adios!
  136. request.messages.set_flash(Message(_("Your avatar has changed.")), 'success', 'usercp_avatar')
  137. return redirect(reverse('usercp_avatar'))
  138. except ValidationError:
  139. request.user.delete_avatar()
  140. request.user.default_avatar(request.settings)
  141. message = Message(_("Only gif, jpeg and png files are allowed for member avatars."), 'error')
  142. else:
  143. message = Message(form.non_field_errors()[0], 'error')
  144. else:
  145. form = UploadAvatarForm(request=request)
  146. return request.theme.render_to_response('usercp/avatar_upload.html',
  147. context_instance=RequestContext(request, {
  148. 'message': message,
  149. 'form': FormLayout(form),
  150. 'tab': 'avatar',
  151. }));
  152. @block_guest
  153. @avatar_view
  154. def crop(request, upload=False):
  155. if upload and (not request.user.avatar_temp or not 'upload' in request.settings.avatars_types):
  156. return error404(request)
  157. if not upload and request.user.avatar_type != 'upload':
  158. request.messages.set_flash(Message(_("Crop Avatar option is avaiable only when you use uploaded image as your avatar.")), 'error', 'usercp_avatar')
  159. return redirect(reverse('usercp_avatar'))
  160. message = request.messages.get_message('usercp_avatar')
  161. if request.method == 'POST':
  162. if request.csrf.request_secure(request):
  163. try:
  164. image_path = settings.MEDIA_ROOT + 'avatars/'
  165. if upload:
  166. source = Image.open(image_path + request.user.avatar_temp)
  167. else:
  168. source = Image.open(image_path + request.user.avatar_original)
  169. width, height = source.size
  170. aspect = float(width) / float(request.POST['crop_b'])
  171. crop_x = int(aspect * float(request.POST['crop_x']))
  172. crop_y = int(aspect * float(request.POST['crop_y']))
  173. crop_w = int(aspect * float(request.POST['crop_w']))
  174. crop = source.crop((crop_x, crop_y, crop_x + crop_w, crop_y + crop_w))
  175. if upload:
  176. image_name, image_extension = path(request.user.avatar_temp).splitext()
  177. else:
  178. image_name, image_extension = path(request.user.avatar_original).splitext()
  179. image_name = '%s_%s%s' % (request.user.pk, random_string(8), image_extension)
  180. resizeimage(crop, settings.AVATAR_SIZES[0], image_path + image_name, info=source.info, format=source.format)
  181. for size in settings.AVATAR_SIZES[1:]:
  182. resizeimage(crop, size, image_path + str(size) + '_' + image_name, info=source.info, format=source.format)
  183. request.user.delete_avatar_image()
  184. if upload:
  185. request.user.delete_avatar_original()
  186. request.user.avatar_type = 'upload'
  187. request.user.avatar_original = '%s_org_%s%s' % (request.user.pk, random_string(8), image_extension)
  188. source.save(image_path + request.user.avatar_original)
  189. request.user.delete_avatar_temp()
  190. request.user.avatar_image = image_name
  191. request.user.save(force_update=True)
  192. request.messages.set_flash(Message(_("Your avatar has been cropped.")), 'success', 'usercp_avatar')
  193. return redirect(reverse('usercp_avatar'))
  194. except Exception:
  195. message = Message(_("Form contains errors."), 'error')
  196. else:
  197. message = Message(_("Request authorisation is invalid."), 'error')
  198. return request.theme.render_to_response('usercp/avatar_crop.html',
  199. context_instance=RequestContext(request, {
  200. 'message': message,
  201. 'after_upload': upload,
  202. 'avatar_size': settings.AVATAR_SIZES[0],
  203. 'source': 'avatars/%s' % (request.user.avatar_temp if upload else request.user.avatar_original),
  204. 'tab': 'avatar',
  205. }));