From b151192d024ff9af67edde7eb1f8fd4137fd1276 Mon Sep 17 00:00:00 2001 From: Thomas Steen Rasmussen Date: Fri, 17 Mar 2017 19:40:47 +0100 Subject: [PATCH] refactor some of the common image code into a PictureViewMixin, and make pictures work with the devserver --- src/program/mixins.py | 41 ++++++++++++++++++++++++++++ src/program/views.py | 62 +++++-------------------------------------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/program/mixins.py b/src/program/mixins.py index 34004532..02be79a3 100644 --- a/src/program/mixins.py +++ b/src/program/mixins.py @@ -3,6 +3,8 @@ from django.shortcuts import redirect from django.urls import reverse from . import models from django.contrib import messages +import sys, mimetypes +from django.http import Http404, HttpResponse class CreateProposalMixin(SingleObjectMixin): @@ -46,3 +48,42 @@ class EnsureUserOwnsProposalMixin(SingleObjectMixin): # alright, continue with the request 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 + + diff --git a/src/program/views.py b/src/program/views.py index 5f4ad498..9269c176 100644 --- a/src/program/views.py +++ b/src/program/views.py @@ -9,7 +9,7 @@ from django.contrib import messages from django.shortcuts import redirect from django.urls import reverse from camps.mixins import CampViewMixin -from .mixins import CreateProposalMixin, EnsureUnapprovedProposalMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin +from .mixins import CreateProposalMixin, EnsureUnapprovedProposalMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin, PictureViewMixin from . import models import datetime, os @@ -77,7 +77,7 @@ class SpeakerProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwn @method_decorator(require_safe, name='dispatch') -class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView): +class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, PictureViewMixin, DetailView): model = models.SpeakerProposal def get(self, request, *args, **kwargs): @@ -85,31 +85,8 @@ class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOw if 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: - # 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'] = '' + # get and return the response + response = self.get_picture_response() return response @@ -163,38 +140,11 @@ class EventProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsP @method_decorator(require_safe, name='dispatch') -class SpeakerPictureView(CampViewMixin, DetailView): +class SpeakerPictureView(CampViewMixin, PictureViewMixin, DetailView): model = models.Speaker def get(self, request, *args, **kwargs): - # is the speaker public, or owned by current user? - 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'] = '' + response = self.get_picture_response() return response