Esempio n. 1
0
def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString,
               subevent: SubEvent, refund_amount: Decimal, user: User,
               positions: list):
    with language(order.locale, order.event.settings.region):
        try:
            ia = order.invoice_address
        except InvoiceAddress.DoesNotExist:
            ia = InvoiceAddress(order=order)

        email_context = get_email_context(event_or_subevent=subevent
                                          or order.event,
                                          refund_amount=refund_amount,
                                          order=order,
                                          position_or_address=ia,
                                          event=order.event)
        real_subject = str(subject).format_map(TolerantDict(email_context))
        try:
            order.send_mail(
                real_subject,
                message,
                email_context,
                'pretix.event.order.email.event_canceled',
                user,
            )
        except SendMailException:
            logger.exception('Order canceled email could not be sent')

        for p in positions:
            if subevent and p.subevent_id != subevent.id:
                continue

            if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
                real_subject = str(subject).format_map(
                    TolerantDict(email_context))
                email_context = get_email_context(event_or_subevent=p.subevent
                                                  or order.event,
                                                  event=order.event,
                                                  refund_amount=refund_amount,
                                                  position_or_address=p,
                                                  order=order,
                                                  position=p)
                try:
                    order.send_mail(real_subject,
                                    message,
                                    email_context,
                                    'pretix.event.order.email.event_canceled',
                                    position=p,
                                    user=user)
                except SendMailException:
                    logger.exception(
                        'Order canceled email could not be sent to attendee')
Esempio n. 2
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        o = {}

        for lang in self.request.event.settings.locales:
            with language(lang, self.request.event.settings.region):
                placeholders = TolerantDict()
                for k, v in get_available_placeholders(self.request.event, ['event', 'order', 'position_or_address']).items():
                    placeholders[k] = '<span class="placeholder" title="{}">{}</span>'.format(
                        _('This value will be replaced based on dynamic parameters.'),
                        v.render_sample(self.request.event)
                    )

                subject = bleach.clean(self.object.subject.localize(lang), tags=[])
                preview_subject = subject.format_map(placeholders)
                template = self.object.template.localize(lang)
                preview_text = markdown_compile_email(template.format_map(placeholders))

                o[lang] = {
                    'subject': _('Subject: {subject}'.format(subject=preview_subject)),
                    'html': preview_text,
                }

        ctx['output'] = o

        return ctx
Esempio n. 3
0
def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString,
                   message: LazyI18nString, subevent: SubEvent):
    with language(wle.locale, wle.event.settings.region):
        email_context = get_email_context(event_or_subevent=subevent
                                          or wle.event,
                                          event=wle.event)
        try:
            mail(wle.email,
                 str(subject).format_map(TolerantDict(email_context)),
                 message,
                 email_context,
                 wle.event,
                 locale=wle.locale)
        except SendMailException:
            logger.exception('Waiting list canceled email could not be sent')
Esempio n. 4
0
    def form_valid(self, form):
        self.output = {}

        if self.request.POST.get("action") == "preview":
            for l in self.request.event.settings.locales:
                with language(l, self.request.event.settings.region):
                    context_dict = TolerantDict()
                    for k, v in get_available_placeholders(
                            self.request.event,
                        ['event', 'order', 'position_or_address']).items():
                        context_dict[
                            k] = '<span class="placeholder" title="{}">{}</span>'.format(
                                _('This value will be replaced based on dynamic parameters.'
                                  ), v.render_sample(self.request.event))

                    subject = bleach.clean(
                        form.cleaned_data['subject'].localize(l), tags=[])
                    preview_subject = subject.format_map(context_dict)
                    template = form.cleaned_data['template'].localize(l)
                    preview_text = markdown_compile_email(
                        template.format_map(context_dict))

                    self.output[l] = {
                        'subject':
                        _('Subject: {subject}').format(
                            subject=preview_subject),
                        'html':
                        preview_text,
                    }

            return self.get(self.request, *self.args, **self.kwargs)

        messages.success(self.request, _('Your rule has been created.'))

        form.instance.event = self.request.event

        self.object = form.save()

        return redirect(
            'plugins:sendmail:rule.update',
            event=self.request.event.slug,
            organizer=self.request.event.organizer.slug,
            rule=self.object.pk,
        )
Esempio n. 5
0
    def form_valid(self, form):
        qs = Order.objects.filter(event=self.request.event)
        statusq = Q(status__in=form.cleaned_data['sendto'])
        if 'overdue' in form.cleaned_data['sendto']:
            statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now())
        orders = qs.filter(statusq)

        opq = OrderPosition.objects.filter(
            order=OuterRef('pk'),
            canceled=False,
            item_id__in=[i.pk for i in form.cleaned_data.get('items')],
        )

        if form.cleaned_data.get('filter_checkins'):
            ql = []
            if form.cleaned_data.get('not_checked_in'):
                ql.append(Q(checkins__list_id=None))
            if form.cleaned_data.get('checkin_lists'):
                ql.append(
                    Q(checkins__list_id__in=[
                        i.pk
                        for i in form.cleaned_data.get('checkin_lists', [])
                    ], ))
            if len(ql) == 2:
                opq = opq.filter(ql[0] | ql[1])
            elif ql:
                opq = opq.filter(ql[0])
            else:
                opq = opq.none()

        if form.cleaned_data.get('subevent'):
            opq = opq.filter(subevent=form.cleaned_data.get('subevent'))

        orders = orders.annotate(match_pos=Exists(opq)).filter(
            match_pos=True).distinct()

        self.output = {}
        if not orders:
            messages.error(self.request,
                           _('There are no orders matching this selection.'))
            return self.get(self.request, *self.args, **self.kwargs)

        if self.request.POST.get("action") == "preview":
            for l in self.request.event.settings.locales:

                with language(l):
                    context_dict = TolerantDict()
                    for k, v in get_available_placeholders(
                            self.request.event,
                        ['event', 'order', 'position_or_address']).items():
                        context_dict[
                            k] = '<span class="placeholder" title="{}">{}</span>'.format(
                                _('This value will be replaced based on dynamic parameters.'
                                  ), v.render_sample(self.request.event))

                    subject = bleach.clean(
                        form.cleaned_data['subject'].localize(l), tags=[])
                    preview_subject = subject.format_map(context_dict)
                    message = form.cleaned_data['message'].localize(l)
                    preview_text = markdown_compile_email(
                        message.format_map(context_dict))

                    self.output[l] = {
                        'subject':
                        _('Subject: {subject}').format(
                            subject=preview_subject),
                        'html':
                        preview_text,
                    }

            return self.get(self.request, *self.args, **self.kwargs)

        send_mails.apply_async(
            kwargs={
                'recipients':
                form.cleaned_data['recipients'],
                'event':
                self.request.event.pk,
                'user':
                self.request.user.pk,
                'subject':
                form.cleaned_data['subject'].data,
                'message':
                form.cleaned_data['message'].data,
                'orders': [o.pk for o in orders],
                'items': [i.pk for i in form.cleaned_data.get('items')],
                'not_checked_in':
                form.cleaned_data.get('not_checked_in'),
                'checkin_lists':
                [i.pk for i in form.cleaned_data.get('checkin_lists')],
                'filter_checkins':
                form.cleaned_data.get('filter_checkins'),
            })
        self.request.event.log_action('pretix.plugins.sendmail.sent',
                                      user=self.request.user,
                                      data=dict(form.cleaned_data))
        messages.success(
            self.request,
            _('Your message has been queued and will be sent to the contact addresses of %d '
              'orders in the next minutes.') % len(orders))

        return redirect('plugins:sendmail:send',
                        event=self.request.event.slug,
                        organizer=self.request.event.organizer.slug)
Esempio n. 6
0
def get_private_icals(event, positions):
    """
    Return a list of ical objects based on a sequence of positions.

    Unlike get_public_ical, this will

    - Generate multiple ical files instead of one (but with deduplication applied)
    - Respect the mail_attach_ical_description setting

    It is private in the sense that mail_attach_ical_description may contain content not suited for
    public display.

    We however intentionally do not allow using placeholders based on the order and position
    specifically. This is for two reasons:

    - In reality, many people will add their invite to their calendar which is shared with a larger
      team. People are probably not aware that they're sharing sensitive information such as their
      secret ticket link with everyone they share their calendar with.

    - It would be pretty hard to implement it in a way that doesn't require us to use distinct
      settings fields for emails to customers and to attendees, which feels like an overcomplication.
    """

    from pretix.base.services.mail import TolerantDict

    tz = pytz.timezone(event.settings.timezone)

    creation_time = datetime.datetime.now(pytz.utc)
    calobjects = []

    evs = set(p.subevent or event for p in positions)
    for ev in evs:
        if isinstance(ev, Event):
            url = build_absolute_uri(event, 'presale:event.index')
        else:
            url = build_absolute_uri(event, 'presale:event.index', {
                'subevent': ev.pk
            })

        if event.settings.mail_attach_ical_description:
            ctx = get_email_context(event=event, event_or_subevent=ev)
            description = str(event.settings.mail_attach_ical_description).format_map(TolerantDict(ctx))
        else:
            # Default description
            descr = []
            descr.append(_('Tickets: {url}').format(url=url))
            if ev.date_admission:
                descr.append(str(_('Admission: {datetime}')).format(
                    datetime=date_format(ev.date_admission.astimezone(tz), 'SHORT_DATETIME_FORMAT')
                ))

            descr.append(_('Organizer: {organizer}').format(organizer=event.organizer.name))
            description = '\n'.join(descr)

        cal = vobject.iCalendar()
        cal.add('prodid').value = '-//pretix//{}//'.format(settings.PRETIX_INSTANCE_NAME.replace(" ", "_"))

        vevent = cal.add('vevent')
        vevent.add('summary').value = str(ev.name)
        vevent.add('description').value = description
        vevent.add('dtstamp').value = creation_time
        if ev.location:
            vevent.add('location').value = str(ev.location)

        vevent.add('uid').value = 'pretix-{}-{}-{}@{}'.format(
            event.organizer.slug,
            event.organizer.slug, event.slug,
            ev.pk if not isinstance(ev, Event) else '0',
            urlparse(url).netloc
        )

        if event.settings.show_times:
            vevent.add('dtstart').value = ev.date_from.astimezone(tz)
        else:
            vevent.add('dtstart').value = ev.date_from.astimezone(tz).date()

        if event.settings.show_date_to and ev.date_to:
            if event.settings.show_times:
                vevent.add('dtend').value = ev.date_to.astimezone(tz)
            else:
                # with full-day events date_to in pretix is included (e.g. last day)
                # whereas dtend in vcalendar is non-inclusive => add one day for export
                vevent.add('dtend').value = ev.date_to.astimezone(tz).date() + datetime.timedelta(days=1)

        calobjects.append(cal)
    return calobjects
def book_second_dose(*, op, item, variation, subevent, original_event):
    event = item.event
    with event.lock(), transaction.atomic():
        avcode, avnr = item.check_quotas(subevent=subevent,
                                         fail_on_no_quotas=True)
        if avcode != Quota.AVAILABILITY_OK:
            logger.info(
                f"SECOND DOSE: cannot use slot {subevent.pk}, sold out")
            # sold out, look for next one
            return

        childorder = Order.objects.create(
            event=event,
            status=Order.STATUS_PAID,
            require_approval=False,
            testmode=op.order.testmode,
            email=op.order.email,
            phone=op.order.phone,
            locale=op.order.locale,
            expires=now() + timedelta(days=30),
            total=Decimal("0.00"),
            expiry_reminder_sent=True,
            sales_channel=op.order.sales_channel,
            comment="Auto-generated through scheduling from order {}".format(
                op.order.code),
            meta_info=op.order.meta_info,
        )
        op.order.log_action(
            "pretix_vacc_autosched.scheduled",
            data={
                "position": op.pk,
                "event": event.pk,
                "event_slug": event.slug,
                "order": childorder.code,
            },
        )
        childorder.log_action(
            "pretix_vacc_autosched.created",
            data={
                "event": original_event.pk,
                "event_slug": original_event.slug,
                "order": op.order.code,
            },
        )
        childorder.log_action("pretix.event.order.placed",
                              data={"source": "vacc_autosched"})
        childpos = childorder.positions.create(
            positionid=1,
            tax_rate=Decimal("0.00"),
            tax_rule=None,
            tax_value=Decimal("0.00"),
            subevent=subevent,
            item=item,
            variation=variation,
            price=Decimal("0.00"),
            attendee_name_cached=op.attendee_name_cached,
            attendee_name_parts=op.attendee_name_parts,
            attendee_email=op.attendee_email,
            company=op.company,
            street=op.street,
            zipcode=op.zipcode,
            city=op.city,
            country=op.country,
            state=op.state,
            addon_to=None,
            voucher=None,
            meta_info=op.meta_info,
        )
        for answ in op.answers.all():
            q = childorder.event.questions.filter(
                identifier=answ.question.identifier).first()
            if not q:
                continue
            childansw = childpos.answers.create(question=q,
                                                answer=answ.answer,
                                                file=answ.file)
            if answ.options.all():
                childopts = list(
                    q.options.filter(identifier__in=[
                        o.identifier for o in answ.options.all()
                    ]))
                if childopts:
                    childansw.options.add(*childopts)

        LinkedOrderPosition.objects.create(base_position=op,
                                           child_position=childpos)
        childorder.create_transactions(is_new=True)
    order_placed.send(event, order=childorder)
    order_paid.send(event, order=childorder)

    if original_event.settings.vacc_autosched_mail:
        with language(childorder.locale, original_event.settings.region):
            email_template = original_event.settings.vacc_autosched_body
            email_subject = str(original_event.settings.vacc_autosched_subject)

            email_context = get_email_context(event=childorder.event,
                                              order=childorder)
            email_context["scheduled_datetime"] = date_format(
                subevent.date_from.astimezone(original_event.timezone),
                "SHORT_DATETIME_FORMAT",
            )
            try:
                childorder.send_mail(
                    email_subject,
                    email_template,
                    email_context,
                    "pretix.event.order.email.order_placed",
                    attach_tickets=True,
                    attach_ical=event.settings.mail_attach_ical,
                )
            except SendMailException:
                logger.exception("Order approved email could not be sent")
    if (original_event.settings.vacc_autosched_sms
            and can_use_juvare_api(original_event) and childorder.phone):
        with language(childorder.locale, original_event.settings.region):
            from pretix_juvare_notify.tasks import juvare_send_text

            template = original_event.settings.vacc_autosched_sms_text
            context = get_email_context(event=childorder.event,
                                        order=childorder)
            context["scheduled_datetime"] = date_format(
                subevent.date_from.astimezone(original_event.timezone),
                "SHORT_DATETIME_FORMAT",
            )
            message = str(template).format_map(TolerantDict(context))
            juvare_send_text.apply_async(
                kwargs={
                    "text": message,
                    "to": childorder.phone,
                    "event": original_event.pk,
                })
    logger.info(f"SECOND DOSE: done, created order {childorder.code}")
    return childorder