PageRenderTime 66ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/avatar/views.py

https://github.com/jannon/django-avatar
Python | 220 lines | 177 code | 32 blank | 11 comment | 29 complexity | f078cfa784c5bf956d507d503fb9477c MD5 | raw file
  1. from django.contrib.auth.decorators import login_required
  2. from django.utils.decorators import method_decorator
  3. from django.http import HttpResponseRedirect, HttpResponse
  4. from django.utils.translation import ugettext as _
  5. from django.views.generic.edit import BaseFormView, FormMixin
  6. from django.views.generic.base import TemplateResponseMixin, View
  7. from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm
  8. from avatar.models import Avatar
  9. from avatar.settings import AVATAR_MAX_AVATARS_PER_USER, AVATAR_DEFAULT_SIZE
  10. from avatar.signals import avatar_updated
  11. from avatar.util import get_default_avatar_url
  12. def _get_next(request):
  13. """
  14. The part that's the least straightforward about views in this module is how
  15. they determine their redirects after they have finished computation.
  16. In short, they will try and determine the next place to go in the following
  17. order:
  18. 1. If there is a variable named ``next`` in the *POST* parameters, the view
  19. will redirect to that variable's value.
  20. 2. If there is a variable named ``next`` in the *GET* parameters, the view
  21. will redirect to that variable's value.
  22. 3. If Django can determine the previous page from the HTTP headers, the view
  23. will redirect to that previous page.
  24. """
  25. next = request.POST.get('next', request.GET.get('next',
  26. request.META.get('HTTP_REFERER', None)))
  27. if not next:
  28. next = request.path
  29. return next
  30. def _get_avatars(target):
  31. # Default set. Needs to be sliced, but that's it. Keep the natural order.
  32. avatars = Avatar.objects.avatars_for_object(target)
  33. # Current avatar
  34. primary_avatar = avatars.order_by('-primary')[:1]
  35. if primary_avatar:
  36. avatar = primary_avatar[0]
  37. else:
  38. avatar = None
  39. if AVATAR_MAX_AVATARS_PER_USER == 1:
  40. avatars = primary_avatar
  41. else:
  42. # Slice the default set now that we used the queryset for the primary
  43. # avatar
  44. avatars = avatars[:AVATAR_MAX_AVATARS_PER_USER]
  45. return (avatar, avatars)
  46. class LoginRequiredMixin(object):
  47. @method_decorator(login_required)
  48. def dispatch(self, request, *args, **kwargs):
  49. return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
  50. class AvatarMixin(object):
  51. def get_target(self):
  52. return self.request.user
  53. def get_avatars(self, target):
  54. return _get_avatars(target)
  55. def create_avatar(self, target, avatar_file):
  56. avatar = Avatar(
  57. content_object=target,
  58. primary=True,
  59. )
  60. avatar.avatar.save(avatar_file.name, avatar_file)
  61. avatar.save()
  62. return avatar
  63. def get_success_url(self):
  64. return self.kwargs.get('next_override', None) or _get_next(self.request)
  65. def render_to_response(self, context):
  66. if self.request.is_ajax() or self.request.REQUEST.get('async', None) == 'true':
  67. return self.render_ajax_response(context)
  68. else:
  69. return TemplateResponseMixin.render_to_response(self, context)
  70. def render_ajax_response(self, context):
  71. return TemplateResponseMixin.render_to_response(self, context)
  72. def ajax_form_valid(self, new_avatar):
  73. if not new_avatar:
  74. return HttpResponse()
  75. return HttpResponse(new_avatar.avatar_url(AVATAR_DEFAULT_SIZE))
  76. def get_form_kwargs(self):
  77. kwargs = FormMixin.get_form_kwargs(self)
  78. kwargs['target'] = self.target
  79. kwargs['size'] = self.request.REQUEST.get('size', AVATAR_DEFAULT_SIZE)
  80. return kwargs
  81. def post(self, request, *args, **kwargs):
  82. self.target = self.get_target()
  83. self.avatar, self.avatars = self.get_avatars(self.target)
  84. return super(AvatarMixin, self).post(request, *args, **kwargs)
  85. def get(self, request, *args, **kwargs):
  86. self.target = self.get_target()
  87. self.avatar, self.avatars = self.get_avatars(self.target)
  88. return super(AvatarMixin, self).get(request, *args, **kwargs)
  89. class AddAvatarView(LoginRequiredMixin, AvatarMixin, TemplateResponseMixin, BaseFormView):
  90. form_class = UploadAvatarForm
  91. template_name = "avatar/add.html"
  92. def form_valid(self, form):
  93. new_avatar = self.create_avatar(self.target, self.request.FILES['avatar'])
  94. if new_avatar:
  95. self.request.user.message_set.create(
  96. message=_("Successfully uploaded a new avatar."))
  97. avatar_updated.send(sender=Avatar, target=self.target,
  98. avatar=new_avatar)
  99. if self.request.is_ajax() or self.request.REQUEST.get('async', None) == 'true':
  100. return self.ajax_form_valid(new_avatar)
  101. else:
  102. return FormMixin.form_valid(self, form)
  103. def get_context_data(self, **kwargs):
  104. kwargs['avatar'] = self.avatar
  105. kwargs['avatars'] = self.avatars
  106. kwargs['upload_avatar_form'] = kwargs['form']
  107. kwargs['next'] = self.get_success_url()
  108. return kwargs
  109. class ChangeAvatarView(LoginRequiredMixin, AvatarMixin, TemplateResponseMixin, BaseFormView):
  110. form_class = PrimaryAvatarForm
  111. upload_form_class = UploadAvatarForm
  112. template_name = "avatar/change.html"
  113. def form_valid(self, form):
  114. new_avatar = Avatar.objects.get(id=form.cleaned_data['choice'])
  115. new_avatar.primary = True
  116. new_avatar.save()
  117. self.request.user.message_set.create(
  118. message=_("Avatar successfully updated."))
  119. avatar_updated.send(sender=Avatar, target=self.target, avatar=new_avatar)
  120. if self.request.is_ajax() or self.request.REQUEST.get('async', None) == 'true':
  121. return self.ajax_form_valid(new_avatar)
  122. else:
  123. return FormMixin.form_valid(self, form)
  124. def get_context_data(self, **kwargs):
  125. upload_form = self.upload_form_class(**self.get_form_kwargs())
  126. kwargs['avatar'] = self.avatar
  127. kwargs['avatars'] = self.avatars
  128. kwargs['target'] = self.target
  129. kwargs['primary_avatar_form'] = kwargs['form']
  130. kwargs['upload_avatar_form'] = upload_form
  131. kwargs['next'] = self.get_success_url()
  132. return kwargs
  133. def get_initial(self):
  134. initial = {}
  135. if self.avatar:
  136. initial['choice'] = self.avatar.id
  137. return initial
  138. else:
  139. return self.initial
  140. class DeleteAvatarView(LoginRequiredMixin, AvatarMixin, TemplateResponseMixin, BaseFormView):
  141. form_class = DeleteAvatarForm
  142. template_name = "avatar/confirm_delete.html"
  143. def form_valid(self, form):
  144. ids = form.cleaned_data['choices']
  145. new_avatar = None
  146. if unicode(self.avatar.id) in ids and self.avatars.count() > len(ids):
  147. # Find the next best avatar, and set it as the new primary
  148. for a in self.avatars:
  149. if unicode(a.id) not in ids:
  150. a.primary = True
  151. a.save()
  152. new_avatar = a
  153. avatar_updated.send(sender=Avatar, target=self.target,
  154. avatar=a)
  155. break
  156. Avatar.objects.filter(id__in=ids).delete()
  157. self.request.user.message_set.create(
  158. message=_("Successfully deleted the requested avatars."))
  159. if self.request.is_ajax() or self.request.REQUEST.get('async', None) == 'true':
  160. return self.ajax_form_valid(new_avatar)
  161. else:
  162. return FormMixin.form_valid(self, form)
  163. def get_context_data(self, **kwargs):
  164. kwargs['avatar'] = self.avatar
  165. kwargs['avatars'] = self.avatars
  166. kwargs['delete_avatar_form'] = kwargs['form']
  167. kwargs['next'] = self.get_success_url()
  168. return kwargs
  169. class PrimaryAvatarView(AvatarMixin, View):
  170. def render_primary(self):
  171. size = self.kwargs.get('size', AVATAR_DEFAULT_SIZE)
  172. if self.avatar:
  173. # FIXME: later, add an option to render the resized avatar dynamically
  174. # instead of redirecting to an already created static file. This could
  175. # be useful in certain situations, particularly if there is a CDN and
  176. # we want to minimize the storage usage on our static server, letting
  177. # the CDN store those files instead
  178. return HttpResponseRedirect(self.avatar.avatar_url(size))
  179. else:
  180. url = get_default_avatar_url(self.target, size)
  181. return HttpResponseRedirect(url)
  182. def post(self, request, *args, **kwargs):
  183. super(self.__class__, self).post(request, *args, **kwargs)
  184. return self.render_primary()
  185. def get(self, request, *args, **kwargs):
  186. super(self.__class__, self).get(request, *args, **kwargs)
  187. return self.render_primary()