views.py 12 KB

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