diff --git a/src/pretix/base/forms/widgets.py b/src/pretix/base/forms/widgets.py index 01e7040cc4..3197ad98ee 100644 --- a/src/pretix/base/forms/widgets.py +++ b/src/pretix/base/forms/widgets.py @@ -157,16 +157,12 @@ class TimePickerWidget(forms.TimeInput): class UploadedFileWidget(forms.ClearableFileInput): def __init__(self, *args, **kwargs): - self.position = kwargs.pop('position') - self.event = kwargs.pop('event') self.answer = kwargs.pop('answer') super().__init__(*args, **kwargs) class FakeFile: - def __init__(self, file, container, event, answer): + def __init__(self, file, answer): self.file = file - self.container = container - self.event = event self.answer = answer def __str__(self): @@ -174,25 +170,7 @@ class UploadedFileWidget(forms.ClearableFileInput): @property def url(self): - from pretix.base.models import Order, OrderPosition - from pretix.multidomain.urlreverse import eventreverse - - order = None - if isinstance(self.container, OrderPosition): - order = self.container.order - elif isinstance(self.container, Order): - order = self.container - - if order: - return eventreverse(self.event, 'presale:event.order.download.answer', kwargs={ - 'order': order.code, - 'secret': order.secret, - 'answer': self.answer.pk, - }) - else: - return eventreverse(self.event, 'presale:event.cart.download.answer', kwargs={ - 'answer': self.answer.pk, - }) + return self.answer.frontend_file_url def get_context(self, name, value, attrs): # Browsers can't recognize that the server already has a file uploaded @@ -205,7 +183,7 @@ class UploadedFileWidget(forms.ClearableFileInput): def format_value(self, value): if self.is_initial(value): - return self.FakeFile(value, self.position, self.event, self.answer) + return self.FakeFile(value, self.answer) class SplitDateTimePickerWidget(forms.SplitDateTimeWidget): diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py index d6fa624180..088c84789c 100644 --- a/src/pretix/base/models/items.py +++ b/src/pretix/base/models/items.py @@ -1608,7 +1608,7 @@ class Question(LoggedModel): """ class ContainerType(models.TextChoices): ORDER = "O", _("Order") - ORDERPOSITION = "P", _("Order position") + ORDERPOSITION = "P", _("Order position") TYPE_NUMBER = "N" TYPE_STRING = "S" TYPE_TEXT = "T" diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 2b0d4b69c4..34300993b8 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -1304,10 +1304,9 @@ class Order(LockModel, LoggedModel): def answerfile_name(instance, filename: str) -> str: secret = get_random_string(length=32, allowed_chars=string.ascii_letters + string.digits) - event = (instance.cartposition if instance.cartposition else instance.orderposition.order).event return 'cachedfiles/answers/{org}/{ev}/{secret}.{filename}'.format( - org=event.organizer.slug, - ev=event.slug, + org=instance.event.organizer.slug, + ev=instance.event.slug, secret=secret, filename=escape_uri_path(filename), ) @@ -1369,11 +1368,11 @@ class QuestionAnswer(models.Model): @property def backend_file_url(self): if self.file: - if self.orderposition: + if self.associated_order: return reverse('control:event.order.download.answer', kwargs={ - 'code': self.orderposition.order.code, - 'event': self.orderposition.order.event.slug, - 'organizer': self.orderposition.order.event.organizer.slug, + 'code': self.associated_order.code, + 'event': self.associated_order.event.slug, + 'organizer': self.associated_order.event.organizer.slug, 'answer': self.pk, }) return "" @@ -1383,14 +1382,14 @@ class QuestionAnswer(models.Model): from pretix.multidomain.urlreverse import eventreverse if self.file: - if self.orderposition: - url = eventreverse(self.orderposition.order.event, 'presale:event.order.download.answer', kwargs={ - 'order': self.orderposition.order.code, - 'secret': self.orderposition.order.secret, + if self.associated_order: + url = eventreverse(self.associated_order.event, 'presale:event.order.download.answer', kwargs={ + 'order': self.associated_order.code, + 'secret': self.associated_order.secret, 'answer': self.pk, }) else: - url = eventreverse(self.cartposition.event, 'presale:event.cart.download.answer', kwargs={ + url = eventreverse(self.event, 'presale:event.cart.download.answer', kwargs={ 'answer': self.pk, }) @@ -1405,6 +1404,24 @@ class QuestionAnswer(models.Model): def file_name(self): return self.file.name.split('.', 1)[-1] + @property + def associated_order(self): + if self.orderposition: + return self.orderposition.order + elif self.order: + return self.order + + @property + def event(self): + if self.orderposition: + return self.orderposition.order.event + elif self.cartposition: + return self.cartposition.event + elif self.order: + return self.order.event + elif self.checkoutsession: + return self.checkoutsession.event + def __str__(self): return self.to_string(use_cached=True) diff --git a/src/pretix/control/templates/pretixcontrol/order/fragment_question_answer.html b/src/pretix/control/templates/pretixcontrol/order/fragment_question_answer.html new file mode 100644 index 0000000000..bd8641452b --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/order/fragment_question_answer.html @@ -0,0 +1,28 @@ +{% load safelink %} +{% load i18n %} +{% load rich_text %} +{% if answer %} + {% if answer.file %} + + + {{ answer.file_name }} + + + {% trans "UNSAFE" %} + + {% if answer.is_image %} +
+ + + + {% endif %} + {% elif question.type == "M" %} + {{ answer.to_string_i18n|rich_text_snippet }} + {% else %} + {{ answer.to_string_i18n|linebreaksbr }} + {% endif %} +{% else %} + {% trans "not answered" %} +{% endif %} \ No newline at end of file diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index c013d455b8..94eb286b1c 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -433,7 +433,7 @@ {% endif %} {% for ans in order.answers.all %}
{{ ans.question.internal_name|default:ans.question.question }}
-
{{ ans.answer }}
+
{% include "pretixcontrol/order/fragment_question_answer.html" with request=request question=ans.question answer=ans %}
{% endfor %} @@ -672,31 +672,7 @@ {% endif %}
- {% if q.answer %} - {% if q.answer.file %} - - - {{ q.answer.file_name }} - - - {% trans "UNSAFE" %} - - {% if q.answer.is_image %} -
- - - - {% endif %} - {% elif q.type == "M" %} - {{ q.answer.to_string_i18n|rich_text_snippet }} - {% else %} - {{ q.answer.to_string_i18n|linebreaksbr }} - {% endif %} - {% else %} - {% trans "not answered" %} - {% endif %} + {% include "pretixcontrol/order/fragment_question_answer.html" with request=request question=q answer=q.answer %}
{% endfor %} {% for q in line.additional_fields %} diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 3f0e8867f3..86c4d5a48d 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -2591,7 +2591,11 @@ class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView): answid = kwargs.get('answer') token = request.GET.get('token', '') - answer = get_object_or_404(QuestionAnswer, orderposition__order=self.order, id=answid) + answer = get_object_or_404( + QuestionAnswer, + Q(orderposition__order=self.order) | Q(order=self.order), + id=answid + ) if not answer.file: raise Http404() if not check_token(request, answer, token): @@ -2601,7 +2605,7 @@ class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView): 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, + answer.orderposition.positionid if answer.orderposition else '', os.path.basename(answer.file.name).split('.', 1)[1] ) return resp diff --git a/src/pretix/presale/checkoutflow.py b/src/pretix/presale/checkoutflow.py index 7e206a9e86..0507932a53 100644 --- a/src/pretix/presale/checkoutflow.py +++ b/src/pretix/presale/checkoutflow.py @@ -1564,6 +1564,7 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep): ctx['addr'] = self.invoice_address ctx['confirm_messages'] = self.confirm_messages ctx['cart_session'] = self.cart_session + ctx['checkout_session'] = self.checkout_session ctx['invoice_address_asked'] = self.address_asked ctx['customer'] = self.cart_customer diff --git a/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html b/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html index b6b7024bcb..effc073e30 100644 --- a/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html +++ b/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html @@ -162,6 +162,26 @@ {% endfor %} + {% if checkout_session.answers.all %} +
+
+

+ {% trans "Additional order information" %} + + {% trans "Modify" %} + +

+
+
+
+ {% for ans in checkout_session.answers.all %} +
{{ ans.question.question }}
+
{% include "pretixpresale/event/fragment_question_answer.html" with request=request question=ans.question answer=ans %}
+ {% endfor %} +
+
+
+ {% endif %} {% if confirm_messages %} diff --git a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html index 92f388a521..cdffab8282 100644 --- a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html +++ b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html @@ -206,27 +206,7 @@ {% for q in line.questions %}
{{ q.question }}
- {% if q.answer %} - {% if q.answer.file %} - - - {{ q.answer.file_name }} - - {% if q.answer.is_image %} -
- - {% trans - - {% endif %} - {% elif q.type == "M" %} - {{ q.answer|rich_text_snippet }} - {% else %} - {{ q.answer|linebreaksbr }} - {% endif %} - {% else %} - {% trans "not answered" %} - {% endif %} + {% include "pretixpresale/event/fragment_question_answer.html" with request=request question=q answer=q.answer %}
{% endfor %} {% for q in line.additional_answers %} diff --git a/src/pretix/presale/templates/pretixpresale/event/fragment_question_answer.html b/src/pretix/presale/templates/pretixpresale/event/fragment_question_answer.html new file mode 100644 index 0000000000..bb4e0dfd36 --- /dev/null +++ b/src/pretix/presale/templates/pretixpresale/event/fragment_question_answer.html @@ -0,0 +1,24 @@ +{% load safelink %} +{% load i18n %} +{% load rich_text %} +{% if answer %} + {% if answer.file %} + + + {{ answer.file_name }} + + {% if answer.is_image %} +
+ + {% trans + + {% endif %} + {% elif question.type == "M" %} + {{ answer|rich_text_snippet }} + {% else %} + {{ answer|linebreaksbr }} + {% endif %} +{% else %} + {% trans "not answered" %} +{% endif %} \ No newline at end of file diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py index ab84b8401a..79d3798da2 100644 --- a/src/pretix/presale/views/cart.py +++ b/src/pretix/presale/views/cart.py @@ -388,6 +388,7 @@ def get_or_create_cart_id(request, create=True): if 'carts' in request.session: request.session['carts'][current_id] = {} else: + # We found a valid, existing cart. return current_id cart_data = {} @@ -398,6 +399,7 @@ def get_or_create_cart_id(request, create=True): cart_data['widget_data'] = cached_widget_data else: if not create: + # There is no existing cart for this request and we're not supposed to create a new one. return None new_id = generate_cart_id(request, prefix=prefix) @@ -846,9 +848,10 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView class AnswerDownload(EventViewMixin, View): def get(self, request, *args, **kwargs): answid = kwargs.get('answer') + cart_id = get_or_create_cart_id(self.request) answer = get_object_or_404( QuestionAnswer, - cartposition__cart_id=get_or_create_cart_id(self.request), + Q(cartposition__cart_id=cart_id) | Q(checkoutsession__cart_id=cart_id), id=answid ) if not answer.file: