Add a file upload type to questions (#534)

* Initial stuff

* More features
This commit is contained in:
Raphael Michel
2017-07-03 14:22:31 +02:00
committed by GitHub
parent 678d510e29
commit 0db5d062be
18 changed files with 334 additions and 20 deletions

View File

@@ -1,14 +1,17 @@
import mimetypes
import os
from django.contrib import messages
from django.db.models import Count, Q
from django.http import JsonResponse
from django.shortcuts import redirect
from django.http import FileResponse, Http404, JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils import translation
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from django.views.generic import TemplateView, View
from pretix.base.decimal import round_decimal
from pretix.base.models import CartPosition, Quota, Voucher
from pretix.base.models import CartPosition, QuestionAnswer, Quota, Voucher
from pretix.base.services.cart import (
CartError, add_items_to_cart, clear_cart, remove_cart_position,
)
@@ -266,3 +269,23 @@ class RedeemView(EventViewMixin, TemplateView):
return redirect(eventreverse(request.event, 'presale:event.index'))
return super().dispatch(request, *args, **kwargs)
class AnswerDownload(EventViewMixin, View):
def get(self, request, *args, **kwargs):
answid = kwargs.get('answer')
answer = get_object_or_404(
QuestionAnswer,
cartposition__cart_id=self.request.session.session_key,
id=answid
)
if not answer.file:
return Http404()
ftype, _ = mimetypes.guess_type(answer.file.name)
resp = FileResponse(answer.file, content_type=ftype or 'application/binary')
resp['Content-Disposition'] = 'attachment; filename="{}-cart-{}"'.format(
self.request.event.slug.upper(),
os.path.basename(answer.file.name).split('.', 1)[1]
)
return resp

View File

@@ -1,15 +1,18 @@
import mimetypes
import os
from django.contrib import messages
from django.db import transaction
from django.db.models import Sum
from django.http import FileResponse, Http404, JsonResponse
from django.shortcuts import redirect, render
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView, View
from pretix.base.models import CachedTicket, Invoice, Order, OrderPosition
from pretix.base.models.orders import InvoiceAddress
from pretix.base.models.orders import InvoiceAddress, QuestionAnswer
from pretix.base.payment import PaymentException
from pretix.base.services.invoices import (
generate_cancellation, generate_invoice, invoice_pdf, invoice_qualified,
@@ -29,13 +32,13 @@ from pretix.presale.views.questions import QuestionsViewMixin
class OrderDetailMixin:
@cached_property
def order(self):
try:
order = self.request.event.orders.get(code=self.kwargs['order'])
order = self.request.event.orders.filter(code=self.kwargs['order']).select_related('event').first()
if order:
if order.secret.lower() == self.kwargs['secret'].lower():
return order
else:
return None
except Order.DoesNotExist:
else:
# Do a comparison as well to harden timing attacks
if 'abcdefghijklmnopq'.lower() == self.kwargs['secret'].lower():
return None
@@ -89,7 +92,7 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TemplateView):
ctx['download_buttons'] = self.download_buttons
ctx['cart'] = self.get_cart(
answers=True, downloads=ctx['can_download'],
queryset=OrderPosition.objects.filter(order=self.order),
queryset=self.order.positions.all(),
payment_fee=self.order.payment_fee, payment_fee_tax_rate=self.order.payment_fee_tax_rate
)
ctx['invoices'] = list(self.order.invoices.all())
@@ -488,6 +491,23 @@ class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
return _('The order has been canceled.')
class AnswerDownload(EventViewMixin, OrderDetailMixin, View):
def get(self, request, *args, **kwargs):
answid = kwargs.get('answer')
answer = get_object_or_404(QuestionAnswer, orderposition__order=self.order, id=answid)
if not answer.file:
return Http404()
ftype, _ = mimetypes.guess_type(answer.file.name)
resp = FileResponse(answer.file, content_type=ftype or 'application/binary')
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}"'.format(
self.request.event.slug.upper(), self.order.code,
answer.orderposition.positionid,
os.path.basename(answer.file.name).split('.', 1)[1]
)
return resp
class OrderDownload(EventViewMixin, OrderDetailMixin, View):
def get_self_url(self):

View File

@@ -2,6 +2,7 @@ import json
from collections import defaultdict
from django import forms
from django.core.files.uploadedfile import UploadedFile
from django.utils.functional import cached_property
from pretix.base.models import CartPosition, OrderPosition, QuestionAnswer
@@ -39,7 +40,8 @@ class QuestionsViewMixin:
prefix=cr.id,
cartpos=cartpos,
orderpos=orderpos,
data=(self.request.POST if self.request.method == 'POST' else None))
data=(self.request.POST if self.request.method == 'POST' else None),
files=(self.request.FILES if self.request.method == 'POST' else None))
form.pos = cartpos or orderpos
if len(form.fields) > 0:
formlist.append(form)
@@ -78,7 +80,9 @@ class QuestionsViewMixin:
if hasattr(field, 'answer'):
# We already have a cached answer object, so we don't
# have to create a new one
if v == '':
if v == '' or v is None or (isinstance(field, forms.FileField) and v is False):
if field.answer.file:
field.answer.file.delete()
field.answer.delete()
else:
self._save_to_answer(field, field.answer, v)
@@ -119,5 +123,9 @@ class QuestionsViewMixin:
answer.options.clear()
answer.options.add(value)
answer.answer = value.answer
elif isinstance(field, forms.FileField):
if isinstance(value, UploadedFile):
answer.file.save(value.name, value)
answer.answer = 'file://' + value.name
else:
answer.answer = value