refactor some of the common image code into a PictureViewMixin, and make pictures work with the devserver

This commit is contained in:
Thomas Steen Rasmussen 2017-03-17 19:40:47 +01:00
parent c532dac146
commit b151192d02
2 changed files with 47 additions and 56 deletions

View file

@ -3,6 +3,8 @@ from django.shortcuts import redirect
from django.urls import reverse from django.urls import reverse
from . import models from . import models
from django.contrib import messages from django.contrib import messages
import sys, mimetypes
from django.http import Http404, HttpResponse
class CreateProposalMixin(SingleObjectMixin): class CreateProposalMixin(SingleObjectMixin):
@ -46,3 +48,42 @@ class EnsureUserOwnsProposalMixin(SingleObjectMixin):
# alright, continue with the request # alright, continue with the request
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class PictureViewMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
# do we have the requested picture?
if kwargs['picture'] == 'thumbnail':
if self.get_object().picture_small:
self.picture = self.get_object().picture_small
else:
raise Http404()
elif kwargs['picture'] == 'large':
if self.get_object().picture_large:
self.picture = self.get_object().picture_large
else:
raise Http404()
else:
# only 'thumbnail' and 'large' pictures supported
raise Http404()
# alright, continue with the request
return super().dispatch(request, *args, **kwargs)
def get_picture_response(self):
if 'runserver' in sys.argv or 'runserver_plus' in sys.argv:
# this is a local devserver situation, guess mimetype from extension and return picture directly
response = HttpResponse(self.picture, content_type=mimetypes.types_map[".%s" % self.picture.name.split(".")[-1]])
else:
# make nginx serve the picture using X-Accel-Redirect
# (this works for nginx only, other webservers use x-sendfile)
# maybe make the header name configurable
response = HttpResponse()
response['X-Accel-Redirect'] = '/public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % {
'campslug': self.camp.slug,
'proposaluuid': self.get_object().uuid,
'filename': os.path.basename(self.picture.name),
}
response['Content-Type'] = ''
return response

View file

@ -9,7 +9,7 @@ from django.contrib import messages
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse from django.urls import reverse
from camps.mixins import CampViewMixin from camps.mixins import CampViewMixin
from .mixins import CreateProposalMixin, EnsureUnapprovedProposalMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin from .mixins import CreateProposalMixin, EnsureUnapprovedProposalMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin, PictureViewMixin
from . import models from . import models
import datetime, os import datetime, os
@ -77,7 +77,7 @@ class SpeakerProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwn
@method_decorator(require_safe, name='dispatch') @method_decorator(require_safe, name='dispatch')
class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView): class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, PictureViewMixin, DetailView):
model = models.SpeakerProposal model = models.SpeakerProposal
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -85,31 +85,8 @@ class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOw
if self.get_object().user != request.user: if self.get_object().user != request.user:
raise Http404() raise Http404()
# do we have the requested picture? # get and return the response
if kwargs['picture'] == 'thumbnail': response = self.get_picture_response()
if self.get_object().picture_small:
picture = self.get_object().picture_small
else:
raise Http404()
elif kwargs['picture'] == 'large':
if self.get_object().picture_large:
picture = self.get_object().picture_large
else:
raise Http404()
else:
# only 'thumbnail' and 'large' pictures supported
raise Http404()
# make nginx return the picture using X-Accel-Redirect
# (this works for nginx only, other webservers use x-sendfile),
# TODO: what about runserver mode here?
response = HttpResponse()
response['X-Accel-Redirect'] = '/public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % {
'campslug': self.camp.slug,
'proposaluuid': self.get_object().uuid,
'filename': os.path.basename(picture.name),
}
response['Content-Type'] = ''
return response return response
@ -163,38 +140,11 @@ class EventProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsP
@method_decorator(require_safe, name='dispatch') @method_decorator(require_safe, name='dispatch')
class SpeakerPictureView(CampViewMixin, DetailView): class SpeakerPictureView(CampViewMixin, PictureViewMixin, DetailView):
model = models.Speaker model = models.Speaker
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# is the speaker public, or owned by current user? response = self.get_picture_response()
if not self.get_object().is_public and self.get_object().user != request.user:
raise Http404()
# do we have the requested picture?
if kwargs['picture'] == 'thumbnail':
if self.get_object().picture_small:
picture = self.get_object().picture_small
else:
raise Http404()
elif kwargs['picture'] == 'large':
if self.get_object().picture_large:
picture = self.get_object().picture_large
else:
raise Http404()
else:
raise Http404()
# make nginx return the picture using X-Accel-Redirect
# (this works for nginx only, other webservers use x-sendfile),
# TODO: what about runserver mode here?
response = HttpResponse()
response['X-Accel-Redirect'] = '/public/speakers/%(campslug)s/%(speakerslug)s/%(filename)s' % {
'campslug': self.camp.slug,
'speakerslug': self.get_object().slug,
'filename': os.path.basename(picture.name),
}
response['Content-Type'] = ''
return response return response