forked from CGM_Public/pretix_original
[SECURITY] Tokens for downloading answer attachments
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load eventurl %}
|
||||
{% load safelink %}
|
||||
{% block title %}
|
||||
{% blocktrans trimmed with code=order.code %}
|
||||
Order details: {{ code }}
|
||||
@@ -210,7 +211,10 @@
|
||||
<dd>
|
||||
{% if q.answer %}
|
||||
{% if q.answer.file %}
|
||||
<span class="fa fa-file"></span> {{ q.answer.file_link }}
|
||||
<span class="fa fa-file"></span>
|
||||
<a href="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}">
|
||||
{{ q.answer.file_name }}
|
||||
</a>
|
||||
{% else %}
|
||||
{{ q.answer|linebreaksbr }}
|
||||
{% endif %}
|
||||
|
||||
@@ -128,6 +128,9 @@ urlpatterns = [
|
||||
name='event.order.regeninvoice'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/reissue$', orders.OrderInvoiceReissue.as_view(),
|
||||
name='event.order.reissueinvoice'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/answer/(?P<answer>[^/]+)/$',
|
||||
orders.AnswerDownload.as_view(),
|
||||
name='event.order.download.answer'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/extend$', orders.OrderExtend.as_view(),
|
||||
name='event.order.extend'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/contact$', orders.OrderContactChange.as_view(),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import mimetypes
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
import pytz
|
||||
@@ -6,7 +8,7 @@ from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Count
|
||||
from django.http import FileResponse, Http404, HttpResponseNotAllowed
|
||||
from django.shortcuts import redirect, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
@@ -19,8 +21,8 @@ from i18nfield.strings import LazyI18nString
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import (
|
||||
CachedCombinedTicket, CachedFile, CachedTicket, Invoice, InvoiceAddress,
|
||||
Item, ItemVariation, LogEntry, Order, Quota, generate_position_secret,
|
||||
generate_secret,
|
||||
Item, ItemVariation, LogEntry, Order, QuestionAnswer, Quota,
|
||||
generate_position_secret, generate_secret,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.services.export import export
|
||||
@@ -42,6 +44,7 @@ from pretix.control.forms.orders import (
|
||||
OrderMailForm, OrderPositionAddForm, OrderPositionChangeForm,
|
||||
)
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
from pretix.helpers.safedownload import check_token
|
||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||
from pretix.presale.signals import question_form_fields
|
||||
|
||||
@@ -741,6 +744,29 @@ class OrderEmailHistory(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
return qs
|
||||
|
||||
|
||||
class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
permission = 'can_view_orders'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
answid = kwargs.get('answer')
|
||||
token = request.GET.get('token', '')
|
||||
|
||||
answer = get_object_or_404(QuestionAnswer, orderposition__order=self.order, id=answid)
|
||||
if not answer.file:
|
||||
raise Http404()
|
||||
if not check_token(request, answer, token):
|
||||
raise Http404(_("This link is no longer valid. Please go back, refresh the page, and try again."))
|
||||
|
||||
ftype, ignored = 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 OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/orders/overview.html'
|
||||
permission = 'can_view_orders'
|
||||
|
||||
Reference in New Issue
Block a user