Ejemplo n.º 1
0
def send_update_notification_email():
    gs = GlobalSettingsObject()
    if not gs.settings.update_check_email:
        return

    mail(
        gs.settings.update_check_email,
        _('pretix update available'),
        LazyI18nString.from_gettext(
            ugettext_noop(
                'Hi!\n\nAn update is available for pretix or for one of the plugins you installed in your '
                'pretix installation. Please click on the following link for more information:\n\n {url} \n\n'
                'You can always find information on the latest updates on the pretix.eu blog:\n\n'
                'https://pretix.eu/about/en/blog/'
                '\n\nBest,\n\nyour pretix developers'
            )
        ),
        {
            'url': build_absolute_uri('control:global.update')
        },
    )
Ejemplo n.º 2
0
        'type': str
    },
    'mail_text_signature': {
        'type': LazyI18nString,
        'default': ""
    },
    'mail_text_resend_link': {
        'type':
        LazyI18nString,
        'default':
        LazyI18nString.from_gettext(
            ugettext_noop("""Hello,

you receive this message because you asked us to send you the link
to your order for {event}.

You can change your order details and view the status of your order at
{url}

Best regards,
Your {event} team"""))
    },
    'mail_text_resend_all_links': {
        'type':
        LazyI18nString,
        'default':
        LazyI18nString.from_gettext(
            ugettext_noop("""Hello,

somebody requested a list of your orders for {event}.
The list is as follows:
Ejemplo n.º 3
0
hierarkey.add_default('cfp_biography_min_length', None, int)
hierarkey.add_default('cfp_abstract_max_length', None, int)
hierarkey.add_default('cfp_description_max_length', None, int)
hierarkey.add_default('cfp_biography_max_length', None, int)

hierarkey.add_default('allow_override_votes', 'False', bool)
hierarkey.add_default('review_min_score', 0, int)
hierarkey.add_default('review_max_score', 1, int)
hierarkey.add_default('review_score_mandatory', 'False', bool)
hierarkey.add_default('review_text_mandatory', 'False', bool)
hierarkey.add_default('review_deadline', None, datetime)
hierarkey.add_default(
    'review_help_text',
    LazyI18nString.from_gettext(
        ugettext_noop(
            "Please give a fair review on why you'd like to see this submission at the conference, or why you think it would not be a good fit."
        )
    ),
    LazyI18nString,
)

hierarkey.add_default('mail_from', '', str)
hierarkey.add_default('mail_subject_prefix', '', str)
hierarkey.add_default('mail_signature', '', str)
hierarkey.add_default('smtp_use_custom', 'False', bool)
hierarkey.add_default('smtp_host', '', str)
hierarkey.add_default('smtp_port', '587', int)
hierarkey.add_default('smtp_username', '', str)
hierarkey.add_default('smtp_password', '', str)
hierarkey.add_default('smtp_use_tls', 'True', bool)
hierarkey.add_default('smtp_use_ssl', 'False', bool)
Ejemplo n.º 4
0
from django.utils.translation import ugettext_lazy as _
from i18nfield.strings import LazyI18nString

WELCOME_MEMBER_SUBJECT = LazyI18nString.from_gettext(_('Welcome, latest member!'))
WELCOME_MEMBER_TEXT = LazyI18nString.from_gettext(
    _(
        '''Hi,

welcome to {name}! You're now officially our latest member. Your member ID
is {number}. If you have any questions relating to your member fees or
you want to update your member data, please contact us at {contact}.

{additional_information}

Thanks,
the robo clerk'''
    )
)

WELCOME_OFFICE_SUBJECT = LazyI18nString.from_gettext(_('[byro] New member'))
WELCOME_OFFICE_TEXT = LazyI18nString.from_gettext(
    _(
        '''Hi,

we have a new member: {member_name}

{additional_information}

Thanks,
the robo clerk'''
    )
Ejemplo n.º 5
0
    def test_create_event_success(self):
        doc = self.get_doc('/control/events/add')
        tabletext = doc.select("form")[0].text
        self.assertIn("CCC", tabletext)
        self.assertNotIn("MRM", tabletext)

        doc = self.post_doc(
            '/control/events/add', {
                'event_wizard-current_step': 'foundation',
                'foundation-organizer': self.orga1.pk,
                'foundation-locales': ('en', 'de')
            })
        assert doc.select("#id_basics-name_0")
        assert doc.select("#id_basics-name_1")

        doc = self.post_doc(
            '/control/events/add', {
                'event_wizard-current_step': 'basics',
                'basics-name_0': '33C3',
                'basics-name_1': '33C3',
                'basics-slug': '33c3',
                'basics-date_from_0': '2016-12-27',
                'basics-date_from_1': '10:00:00',
                'basics-date_to_0': '2016-12-30',
                'basics-date_to_1': '19:00:00',
                'basics-location_0': 'Hamburg',
                'basics-location_1': 'Hamburg',
                'basics-currency': 'EUR',
                'basics-tax_rate': '19.00',
                'basics-locale': 'en',
                'basics-timezone': 'Europe/Berlin',
                'basics-presale_start_0': '2016-11-01',
                'basics-presale_start_1': '10:00:00',
                'basics-presale_end_0': '2016-11-30',
                'basics-presale_end_1': '18:00:00',
            })

        assert doc.select("#id_copy-copy_from_event_1")

        self.post_doc('/control/events/add', {
            'event_wizard-current_step': 'copy',
            'copy-copy_from_event': ''
        })

        ev = Event.objects.get(slug='33c3')
        assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'})
        assert ev.settings.locales == ['en', 'de']
        assert ev.settings.locale == 'en'
        assert ev.currency == 'EUR'
        assert ev.settings.timezone == 'Europe/Berlin'
        assert ev.organizer == self.orga1
        assert ev.location == LazyI18nString({
            'de': 'Hamburg',
            'en': 'Hamburg'
        })
        assert Team.objects.filter(limit_events=ev, members=self.user).exists()

        berlin_tz = timezone('Europe/Berlin')
        assert ev.date_from == berlin_tz.localize(
            datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc)
        assert ev.date_to == berlin_tz.localize(
            datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc)
        assert ev.presale_start == berlin_tz.localize(
            datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
        assert ev.presale_end == berlin_tz.localize(
            datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)

        assert ev.tax_rules.filter(rate=Decimal('19.00')).exists()
Ejemplo n.º 6
0
def cancel_event(self,
                 event: Event,
                 subevent: int,
                 auto_refund: bool,
                 keep_fee_fixed: str,
                 keep_fee_per_ticket: str,
                 keep_fee_percentage: str,
                 keep_fees: list = None,
                 manual_refund: bool = False,
                 send: bool = False,
                 send_subject: dict = None,
                 send_message: dict = None,
                 send_waitinglist: bool = False,
                 send_waitinglist_subject: dict = {},
                 send_waitinglist_message: dict = {},
                 user: int = None,
                 refund_as_giftcard: bool = False,
                 giftcard_expires=None,
                 giftcard_conditions=None,
                 subevents_from: str = None,
                 subevents_to: str = None):
    send_subject = LazyI18nString(send_subject)
    send_message = LazyI18nString(send_message)
    send_waitinglist_subject = LazyI18nString(send_waitinglist_subject)
    send_waitinglist_message = LazyI18nString(send_waitinglist_message)
    if user:
        user = User.objects.get(pk=user)

    s = OrderPosition.objects.filter(
        order=OuterRef('pk')).order_by().values('order').annotate(
            k=Count('id')).values('k')
    orders_to_cancel = event.orders.annotate(
        pcnt=Subquery(s, output_field=IntegerField())).filter(
            status__in=[
                Order.STATUS_PAID, Order.STATUS_PENDING, Order.STATUS_EXPIRED
            ],
            pcnt__gt=0).all()

    if subevent or subevents_from:
        if subevent:
            subevents = event.subevents.filter(pk=subevent)
            subevent = subevents.first()
            subevent_ids = {subevent.pk}
        else:
            subevents = event.subevents.filter(date_from__gte=subevents_from,
                                               date_from__lt=subevents_to)
            subevent_ids = set(subevents.values_list('id', flat=True))

        has_subevent = OrderPosition.objects.filter(
            order_id=OuterRef('pk')).filter(subevent__in=subevents)
        has_other_subevent = OrderPosition.objects.filter(
            order_id=OuterRef('pk')).exclude(subevent__in=subevents)
        orders_to_change = orders_to_cancel.annotate(
            has_subevent=Exists(has_subevent),
            has_other_subevent=Exists(has_other_subevent),
        ).filter(has_subevent=True, has_other_subevent=True)
        orders_to_cancel = orders_to_cancel.annotate(
            has_subevent=Exists(has_subevent),
            has_other_subevent=Exists(has_other_subevent),
        ).filter(has_subevent=True, has_other_subevent=False)

        for se in subevents:
            se.log_action(
                'pretix.subevent.canceled',
                user=user,
            )
            se.active = False
            se.save(update_fields=['active'])
            se.log_action('pretix.subevent.changed',
                          user=user,
                          data={
                              'active': False,
                              '_source': 'cancel_event'
                          })
    else:
        subevents = None
        subevent_ids = set()
        orders_to_change = event.orders.none()
        event.log_action(
            'pretix.event.canceled',
            user=user,
        )

        for i in event.items.filter(active=True):
            i.active = False
            i.save(update_fields=['active'])
            i.log_action('pretix.event.item.changed',
                         user=user,
                         data={
                             'active': False,
                             '_source': 'cancel_event'
                         })
    failed = 0
    total = orders_to_cancel.count() + orders_to_change.count()
    qs_wl = event.waitinglistentries.filter(
        voucher__isnull=True).select_related('subevent')
    if subevents:
        qs_wl = qs_wl.filter(subevent__in=subevents)
    if send_waitinglist:
        total += qs_wl.count()
    counter = 0
    self.update_state(state='PROGRESS', meta={'value': 0})

    for o in orders_to_cancel.only('id', 'total').iterator():
        try:
            fee = Decimal('0.00')
            fee_sum = Decimal('0.00')
            keep_fee_objects = []
            if keep_fees:
                for f in o.fees.all():
                    if f.fee_type in keep_fees:
                        fee += f.value
                        keep_fee_objects.append(f)
                    fee_sum += f.value
            if keep_fee_percentage:
                fee += Decimal(keep_fee_percentage) / Decimal('100.00') * (
                    o.total - fee_sum)
            if keep_fee_fixed:
                fee += Decimal(keep_fee_fixed)
            if keep_fee_per_ticket:
                for p in o.positions.all():
                    if p.addon_to_id is None:
                        fee += min(p.price, Decimal(keep_fee_per_ticket))
            fee = round_decimal(min(fee, o.payment_refund_sum), event.currency)

            _cancel_order(o.pk,
                          user,
                          send_mail=False,
                          cancellation_fee=fee,
                          keep_fees=keep_fee_objects)
            refund_amount = o.payment_refund_sum

            try:
                if auto_refund:
                    _try_auto_refund(o.pk,
                                     manual_refund=manual_refund,
                                     allow_partial=True,
                                     source=OrderRefund.REFUND_SOURCE_ADMIN,
                                     refund_as_giftcard=refund_as_giftcard,
                                     giftcard_expires=giftcard_expires,
                                     giftcard_conditions=giftcard_conditions)
            finally:
                if send:
                    _send_mail(o, send_subject, send_message, subevent,
                               refund_amount, user, o.positions.all())

            counter += 1
            if not self.request.called_directly and counter % max(
                    10, total // 100) == 0:
                self.update_state(
                    state='PROGRESS',
                    meta={'value': round(counter / total * 100, 2)})
        except LockTimeoutException:
            logger.exception("Could not cancel order")
            failed += 1
        except OrderError:
            logger.exception("Could not cancel order")
            failed += 1

    for o in orders_to_change.values_list('id', flat=True).iterator():
        with transaction.atomic():
            o = event.orders.select_for_update().get(pk=o)
            total = Decimal('0.00')
            fee = Decimal('0.00')
            positions = []

            ocm = OrderChangeManager(o, user=user, notify=False)
            for p in o.positions.all():
                if p.subevent_id in subevent_ids:
                    total += p.price
                    ocm.cancel(p)
                    positions.append(p)

                    if keep_fee_per_ticket:
                        if p.addon_to_id is None:
                            fee += min(p.price, Decimal(keep_fee_per_ticket))

            if keep_fee_fixed:
                fee += Decimal(keep_fee_fixed)
            if keep_fee_percentage:
                fee += Decimal(keep_fee_percentage) / Decimal('100.00') * total
            fee = round_decimal(min(fee, o.payment_refund_sum), event.currency)
            if fee:
                f = OrderFee(
                    fee_type=OrderFee.FEE_TYPE_CANCELLATION,
                    value=fee,
                    order=o,
                    tax_rule=o.event.settings.tax_rate_default,
                )
                f._calculate_tax()
                ocm.add_fee(f)

            ocm.commit()
            refund_amount = o.payment_refund_sum - o.total

            if auto_refund:
                _try_auto_refund(o.pk,
                                 manual_refund=manual_refund,
                                 allow_partial=True,
                                 source=OrderRefund.REFUND_SOURCE_ADMIN,
                                 refund_as_giftcard=refund_as_giftcard,
                                 giftcard_expires=giftcard_expires,
                                 giftcard_conditions=giftcard_conditions)

            if send:
                _send_mail(o, send_subject, send_message, subevent,
                           refund_amount, user, positions)

            counter += 1
            if not self.request.called_directly and counter % max(
                    10, total // 100) == 0:
                self.update_state(
                    state='PROGRESS',
                    meta={'value': round(counter / total * 100, 2)})

    if send_waitinglist:
        for wle in qs_wl:
            _send_wle_mail(wle, send_waitinglist_subject,
                           send_waitinglist_message, wle.subevent)

            counter += 1
            if not self.request.called_directly and counter % max(
                    10, total // 100) == 0:
                self.update_state(
                    state='PROGRESS',
                    meta={'value': round(counter / total * 100, 2)})
    return failed
Ejemplo n.º 7
0
    def done(self, form_list, form_dict, **kwargs):
        foundation_data = self.get_cleaned_data_for_step('foundation')
        basics_data = self.get_cleaned_data_for_step('basics')
        copy_data = self.get_cleaned_data_for_step('copy')

        with transaction.atomic(), language(basics_data['locale']):
            event = form_dict['basics'].instance
            event.organizer = foundation_data['organizer']
            event.has_subevents = foundation_data['has_subevents']
            event.testmode = True
            form_dict['basics'].save()
            event.set_active_plugins(
                settings.PRETIX_PLUGINS_DEFAULT.split(","),
                allow_restricted=settings.PRETIX_PLUGINS_DEFAULT.split(","))
            event.save(update_fields=['plugins'])
            event.log_action(
                'pretix.event.added',
                user=self.request.user,
            )

            if not EventWizardBasicsForm.has_control_rights(
                    self.request.user, event.organizer, self.request.session):
                if basics_data["team"] is not None:
                    t = basics_data["team"]
                    t.limit_events.add(event)
                elif event.organizer.settings.event_team_provisioning:
                    t = Team.objects.create(
                        organizer=event.organizer,
                        name=_('Team {event}').format(event=event.name),
                        can_change_event_settings=True,
                        can_change_items=True,
                        can_view_orders=True,
                        can_change_orders=True,
                        can_view_vouchers=True,
                        can_change_vouchers=True)
                    t.members.add(self.request.user)
                    t.limit_events.add(event)

            logdata = {}
            for f in form_list:
                logdata.update({k: v for k, v in f.cleaned_data.items()})
            event.log_action('pretix.event.settings',
                             user=self.request.user,
                             data=logdata)

            if copy_data and copy_data['copy_from_event']:
                from_event = copy_data['copy_from_event']
                event.copy_data_from(from_event)
            elif self.clone_from:
                event.copy_data_from(self.clone_from)
            else:
                event.checkin_lists.create(name=_('Default'),
                                           all_products=True)
                event.set_defaults()

            if basics_data['tax_rate']:
                if not event.settings.tax_rate_default or event.settings.tax_rate_default.rate != basics_data[
                        'tax_rate']:
                    event.settings.tax_rate_default = event.tax_rules.create(
                        name=LazyI18nString.from_gettext(gettext('VAT')),
                        rate=basics_data['tax_rate'])

            event.settings.set('timezone', basics_data['timezone'])
            event.settings.set('locale', basics_data['locale'])
            event.settings.set('locales', foundation_data['locales'])

        if (copy_data and copy_data['copy_from_event']
            ) or self.clone_from or event.has_subevents:
            return redirect(
                reverse('control:event.settings',
                        kwargs={
                            'organizer': event.organizer.slug,
                            'event': event.slug,
                        }) + '?congratulations=1')
        else:
            return redirect(
                reverse('control:event.quick',
                        kwargs={
                            'organizer': event.organizer.slug,
                            'event': event.slug,
                        }) + '?congratulations=1')
Ejemplo n.º 8
0
def test_widget_required():
    f = I18nFormField(widget=I18nTextInput, required=True, localize=True)
    rendered = f.widget.render('foo', LazyI18nString({'de': 'Hallo', 'en': 'Hello'}))
    assert 'required' not in rendered
Ejemplo n.º 9
0
def tax_rule(event):
    return event.tax_rules.create(name=LazyI18nString({
        'en': 'VAT',
        'de': 'MwSt'
    }),
                                  rate=Decimal('19.00'))
Ejemplo n.º 10
0
from i18nfield.strings import LazyI18nString
from django.utils.translation import ugettext_lazy as _

MANDATE_REFERENCE_NOTIFICATION_SUBJECT = LazyI18nString.from_gettext(
    _('SEPA Direct Debit mandate reference notification'))
MANDATE_REFERENCE_NOTIFICATION_TEXT = LazyI18nString.from_gettext(
    _('''Hi,

this is to inform you of the SEPA mandate reference we will be using in the
future to issue direct debits for your {association_name} membership fees.

 Mandate reference: {sepa_mandate_reference}
 Your IBAN on file: {sepa_iban}
 Your BIC:          {sepa_bic}
 
 Our Creditor ID:   {creditor_id}

If you have any questions relating to your member fees or you want to update
your member data, please contact us at {contact}.

{additional_information}

Thanks,
the robo clerk'''))

DEBIT_NOTIFICATION_SUBJECT = LazyI18nString.from_gettext(
    _('SEPA Direct Debit notification'))
DEBIT_NOTIFICATION_TEXT = LazyI18nString.from_gettext(
    _('''Hi,
        
this is to inform you of the SEPA direct debit we'll be issuing based on
Ejemplo n.º 11
0
            kwargs={
                "event": d.get("event_slug"),
                "organizer": logentry.organizer.slug,
                "code": d.get("order"),
            },
        )
        return mark_safe(
            _("This order has been scheduled as the second dose for order {order}"
              ).format(order='<a href="{}">{}</a>'.format(url,
                                                          d.get("order")), ))


settings_hierarkey.add_default("vacc_autosched_mail", False, bool)
settings_hierarkey.add_default(
    "vacc_autosched_subject",
    LazyI18nString.from_gettext(
        gettext_noop("Your second dose: {scheduled_datetime}")),
    LazyI18nString,
)
settings_hierarkey.add_default(
    "vacc_autosched_body",
    LazyI18nString.from_gettext(
        gettext_noop(
            "Hello,\n\n"
            "we scheduled your second dose for {scheduled_datetime}.\n\n"
            "Please find additional information in your ticket attached.\n\n"
            "Best regards,\n"
            "Your {event} team")),
    LazyI18nString,
)
settings_hierarkey.add_default("doistep_record_ip", False, bool)
Ejemplo n.º 12
0
    def form_valid(self, form):
        tz = pytz.timezone(self.request.event.settings.timezone)
        order = Order.objects.get(event=self.request.event,
                                  code=self.kwargs['code'].upper())
        self.preview_output = {}
        try:
            invoice_name = order.invoice_address.name
            invoice_company = order.invoice_address.company
        except InvoiceAddress.DoesNotExist:
            invoice_name = ""
            invoice_company = ""
        with language(order.locale):
            email_context = {
                'event':
                order.event,
                'code':
                order.code,
                'date':
                date_format(order.datetime.astimezone(tz),
                            'SHORT_DATETIME_FORMAT'),
                'expire_date':
                date_format(order.expires, 'SHORT_DATE_FORMAT'),
                'url':
                build_absolute_uri(order.event,
                                   'presale:event.order',
                                   kwargs={
                                       'order': order.code,
                                       'secret': order.secret
                                   }),
                'invoice_name':
                invoice_name,
                'invoice_company':
                invoice_company,
            }

        email_content = form.cleaned_data['message'].format_map(email_context)
        if self.request.POST.get('action') == 'preview':
            self.preview_output = []
            self.preview_output.append(
                _('Subject: {subject}').format(
                    subject=form.cleaned_data['subject']))
            self.preview_output.append(email_content)
            return self.get(self.request, *self.args, **self.kwargs)
        else:
            try:
                with language(order.locale):
                    email_template = LazyI18nString(
                        form.cleaned_data['message'])
                    mail(order.email,
                         form.cleaned_data['subject'],
                         email_template,
                         email_context,
                         self.request.event,
                         locale=order.locale,
                         order=order)
                order.log_action('pretix.event.order.mail_sent',
                                 user=self.request.user,
                                 data={
                                     'subject': form.cleaned_data['subject'],
                                     'message': email_content,
                                     'recipient': form.cleaned_data['sendto'],
                                 })
                messages.success(
                    self.request,
                    _('Your message has been queued and will be sent to {}.'.
                      format(order.email)))
            except SendMailException:
                messages.error(
                    self.request,
                    _('Failed to send mail to the following user: {}'.format(
                        order.email)))
            return super(OrderSendMail, self).form_valid(form)
Ejemplo n.º 13
0
        ).values_list('pk', flat=True))

    for eventpk in events:
        consent_to_checkin.apply(args=(eventpk, ))


settings_hierarkey.add_default('pretix_atfconsent_enabled', False, bool)
settings_hierarkey.add_default(
    'pretix_atfconsent_explanation',
    LazyI18nString.from_gettext(
        gettext_noop(
            "Due to the evolving nature of our event, the following information was not yet available at the time "
            "when you registered for this event.\r\n"
            "\r\n"
            "Please take a moment of your time to read through the provided information and confirm that you agree "
            "with the posted information.\r\n"
            "\r\n"
            "Should you not agree with the conditions outlined, we will unfortunately have to cancel your. In this case "
            "you will be provided with a full refund.\r\n"
            "\r\n"
            "If you would like to actively dispute the conditions below and not wait for us to cancel your order due to "
            "non-agreement of the conditions outlined below, feel free to contact us directly at any time."
        )), LazyI18nString)
settings_hierarkey.add_default(
    'pretix_atfconsent_short_explanation',
    LazyI18nString.from_gettext(
        gettext_noop(
            "Due to the evolving nature of our event, some information was not yet available at the time "
            "when you registered for this event.\r\n"
            "\r\n"
            "Please click the button, take a moment of your time to read through the provided information and confirm "
            "that you agree with the posted information.\r\n"
Ejemplo n.º 14
0
def resolve_i18n_string(i18n_str):
    value = LazyI18nString.from_gettext(_(i18n_str)).data
    return json.dumps({lng: value[lng] for lng, lngname in settings.LANGUAGES if value[lng]}, sort_keys=True)
Ejemplo n.º 15
0
    def done(self, form_list, form_dict, **kwargs):
        foundation_data = self.get_cleaned_data_for_step('foundation')
        basics_data = self.get_cleaned_data_for_step('basics')
        copy_data = self.get_cleaned_data_for_step('copy')

        with transaction.atomic(), language(basics_data['locale']):
            event = form_dict['basics'].instance
            event.organizer = foundation_data['organizer']
            event.plugins = settings.PRETIX_PLUGINS_DEFAULT
            event.has_subevents = foundation_data['has_subevents']
            form_dict['basics'].save()

            has_control_rights = self.request.user.teams.filter(
                organizer=event.organizer, all_events=True, can_change_event_settings=True, can_change_items=True,
                can_change_orders=True, can_change_vouchers=True
            ).exists()
            if not has_control_rights:
                t = Team.objects.create(
                    organizer=event.organizer, name=_('Team {event}').format(event=event.name),
                    can_change_event_settings=True, can_change_items=True,
                    can_view_orders=True, can_change_orders=True, can_view_vouchers=True,
                    can_change_vouchers=True
                )
                t.members.add(self.request.user)
                t.limit_events.add(event)

            if event.has_subevents:
                se = event.subevents.create(
                    name=event.name,
                    date_from=event.date_from,
                    date_to=event.date_to,
                    presale_start=event.presale_start,
                    presale_end=event.presale_end,
                    location=event.location,
                    active=True
                )

            if basics_data['tax_rate']:
                event.settings.tax_rate_default = event.tax_rules.create(
                    name=LazyI18nString.from_gettext(ugettext('VAT')),
                    rate=basics_data['tax_rate']
                )

            logdata = {}
            for f in form_list:
                logdata.update({
                    k: v for k, v in f.cleaned_data.items()
                })
            event.log_action('pretix.event.settings', user=self.request.user, data=logdata)

            if copy_data and copy_data['copy_from_event']:
                from_event = copy_data['copy_from_event']
                event.copy_data_from(from_event)
            elif event.has_subevents:
                event.checkin_lists.create(
                    name=str(se),
                    all_products=True,
                    subevent=se
                )
            else:
                event.checkin_lists.create(
                    name=_('Default'),
                    all_products=True
                )

            event.settings.set('timezone', basics_data['timezone'])
            event.settings.set('locale', basics_data['locale'])
            event.settings.set('locales', foundation_data['locales'])

        if (copy_data and copy_data['copy_from_event']) or event.has_subevents:
            return redirect(reverse('control:event.settings', kwargs={
                'organizer': event.organizer.slug,
                'event': event.slug,
            }) + '?congratulations=1')
        else:
            return redirect(reverse('control:event.quick', kwargs={
                'organizer': event.organizer.slug,
                'event': event.slug,
            }) + '?congratulations=1')
Ejemplo n.º 16
0
def send_mails(event: int, user: int, subject: dict, message: dict, orders: list, items: list, recipients: str) -> None:
    failures = []
    event = Event.objects.get(pk=event)
    user = User.objects.get(pk=user) if user else None
    orders = Order.objects.filter(pk__in=orders, event=event)
    subject = LazyI18nString(subject)
    message = LazyI18nString(message)
    tz = pytz.timezone(event.settings.timezone)

    for o in orders:
        try:
            invoice_name = o.invoice_address.name
            invoice_company = o.invoice_address.company
        except InvoiceAddress.DoesNotExist:
            invoice_name = ""
            invoice_company = ""

        send_to_order = recipients in ('both', 'orders')
        if recipients in ('both', 'attendees'):
            for p in o.positions.prefetch_related('addons'):
                if p.addon_to_id is not None:
                    continue

                if p.item_id not in items and not any(a.item_id in items for a in p.addons.all()):
                    continue

                if not p.attendee_email:
                    if recipients == 'attendees':
                        send_to_order = True
                    continue

                if p.attendee_email == o.email and send_to_order:
                    continue

                try:
                    with language(o.locale):
                        email_context = {
                            'event': event,
                            'code': o.code,
                            'date': date_format(o.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'),
                            'expire_date': date_format(o.expires, 'SHORT_DATE_FORMAT'),
                            'url': build_absolute_uri(event, 'presale:event.order.position', kwargs={
                                'order': o.code,
                                'secret': p.web_secret,
                                'position': p.positionid
                            }),
                            'invoice_name': invoice_name,
                            'invoice_company': invoice_company,
                        }
                        mail(
                            p.attendee_email,
                            subject,
                            message,
                            email_context,
                            event,
                            locale=o.locale,
                            order=o,
                            position=p
                        )
                        o.log_action(
                            'pretix.plugins.sendmail.order.email.sent.attendee',
                            user=user,
                            data={
                                'position': p.positionid,
                                'subject': subject.localize(o.locale).format_map(email_context),
                                'message': message.localize(o.locale).format_map(email_context),
                                'recipient': p.attendee_email
                            }
                        )
                except SendMailException:
                    failures.append(p.attendee_email)

        if send_to_order and o.email:
            try:
                with language(o.locale):
                    email_context = {
                        'event': event,
                        'code': o.code,
                        'date': date_format(o.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'),
                        'expire_date': date_format(o.expires, 'SHORT_DATE_FORMAT'),
                        'url': build_absolute_uri(event, 'presale:event.order.open', kwargs={
                            'order': o.code,
                            'secret': o.secret,
                            'hash': o.email_confirm_hash()
                        }),
                        'invoice_name': invoice_name,
                        'invoice_company': invoice_company,
                    }
                    mail(
                        o.email,
                        subject,
                        message,
                        email_context,
                        event,
                        locale=o.locale,
                        order=o
                    )
                    o.log_action(
                        'pretix.plugins.sendmail.order.email.sent',
                        user=user,
                        data={
                            'subject': subject.localize(o.locale).format_map(email_context),
                            'message': message.localize(o.locale).format_map(email_context),
                            'recipient': o.email
                        }
                    )
            except SendMailException:
                failures.append(o.email)
Ejemplo n.º 17
0
from django.utils.translation import ugettext_noop as _
from i18nfield.strings import LazyI18nString

GENERIC_SUBJECT = LazyI18nString.from_gettext(
    _('Your submission: {submission_title}'))

ACK_TEXT = LazyI18nString.from_gettext(
    _('''Hi!

We have received your submission "{submission_title}" to
{event_name}. We will notify you once we have had time to consider all
submissions, but until then you can see and edit your submission at
{submission_url}.

Please do not hesitate to contact us if you have any questions!

The {event_name} organisers'''))

ACCEPT_TEXT = LazyI18nString.from_gettext(
    _('''Hi!

We are happy to tell you that we accept your submission "{submission_title}"
to {event_name}. Please click this link to confirm your attendance:

    {confirmation_link}

We look forward to seeing you at {event_name} - Please contact us if you have any
questions! We will reach out again before the conference to tell you details
about your slot in the schedule and technical details concerning the room
and presentation tech.
Ejemplo n.º 18
0
def test_custom_id():
    f = I18nFormField(widget=I18nTextInput, required=True, localize=True)
    rendered = f.widget.render('foo', LazyI18nString({'de': 'Hallo', 'en': 'Hello'}), attrs={'id': 'bla'})
    assert 'id="bla_0"' in rendered
    assert 'id="bla_1"' in rendered
Ejemplo n.º 19
0
def send_mails(event: int, user: int, subject: dict, message: dict,
               orders: list) -> None:
    failures = []
    event = Event.objects.get(pk=event)
    user = User.objects.get(pk=user) if user else None
    orders = Order.objects.filter(pk__in=orders)
    subject = LazyI18nString(subject)
    message = LazyI18nString(message)
    tz = pytz.timezone(event.settings.timezone)

    for o in orders:
        try:
            invoice_name = o.invoice_address.name
            invoice_company = o.invoice_address.company
        except InvoiceAddress.DoesNotExist:
            invoice_name = ""
            invoice_company = ""
        try:
            with language(o.locale):
                email_context = {
                    'event':
                    o.event,
                    'code':
                    o.code,
                    'date':
                    date_format(o.datetime.astimezone(tz),
                                'SHORT_DATETIME_FORMAT'),
                    'expire_date':
                    date_format(o.expires, 'SHORT_DATE_FORMAT'),
                    'url':
                    build_absolute_uri(event,
                                       'presale:event.order',
                                       kwargs={
                                           'order': o.code,
                                           'secret': o.secret
                                       }),
                    'invoice_name':
                    invoice_name,
                    'invoice_company':
                    invoice_company,
                }
                mail(o.email,
                     subject,
                     message,
                     email_context,
                     event,
                     locale=o.locale,
                     order=o)
                o.log_action('pretix.plugins.sendmail.order.email.sent',
                             user=user,
                             data={
                                 'subject':
                                 subject.localize(o.locale),
                                 'message':
                                 message.localize(
                                     o.locale).format_map(email_context),
                                 'recipient':
                                 o.email
                             })
        except SendMailException:
            failures.append(o.email)
Ejemplo n.º 20
0
        'type': str
    },
    'mail_text_signature': {
        'type': LazyI18nString,
        'default': ""
    },
    'mail_text_resend_link': {
        'type':
        LazyI18nString,
        'default':
        LazyI18nString.from_gettext(
            ugettext_noop("""Hello,

you receive this message because you asked us to send you the link
to your order for {event}.

You can change your order details and view the status of your order at
{url}

Best regards,
Your {event} team"""))
    },
    'mail_text_resend_all_links': {
        'type':
        LazyI18nString,
        'default':
        LazyI18nString.from_gettext(
            ugettext_noop("""Hello,

somebody requested a list of your orders for {event}.
The list is as follows:
Ejemplo n.º 21
0
from django.utils.translation import ugettext_lazy as _
from i18nfield.strings import LazyI18nString

SUBJECT = LazyI18nString.from_gettext(_('Your Receipt'))
TEXT = LazyI18nString.from_gettext(
    _('''Hi,

This is your official receipt for fees and donations rendered to us last
year.  As the finance autorities usually do not want to see receipts,
and we are not allowed to sign receipts digitally, please keep it like
this. If you need to send it in, come around and we'll sign it.

Thanks,
the robo clerk'''))
Ejemplo n.º 22
0
    def done(self, form_list, form_dict, **kwargs):
        foundation_data = self.get_cleaned_data_for_step('foundation')
        basics_data = self.get_cleaned_data_for_step('basics')
        copy_data = self.get_cleaned_data_for_step('copy')

        with transaction.atomic():
            event = form_dict['basics'].instance
            event.organizer = foundation_data['organizer']
            event.plugins = settings.PRETIX_PLUGINS_DEFAULT
            event.has_subevents = foundation_data['has_subevents']
            form_dict['basics'].save()

            has_control_rights = self.request.user.teams.filter(
                organizer=event.organizer, all_events=True, can_change_event_settings=True, can_change_items=True,
                can_change_orders=True, can_change_vouchers=True
            ).exists()
            if not has_control_rights:
                t = Team.objects.create(
                    organizer=event.organizer, name=_('Team {event}').format(event=event.name),
                    can_change_event_settings=True, can_change_items=True,
                    can_view_orders=True, can_change_orders=True, can_view_vouchers=True,
                    can_change_vouchers=True
                )
                t.members.add(self.request.user)
                t.limit_events.add(event)

            if event.has_subevents:
                event.subevents.create(
                    name=event.name,
                    date_from=event.date_from,
                    date_to=event.date_to,
                    presale_start=event.presale_start,
                    presale_end=event.presale_end,
                    location=event.location,
                    active=True
                )

            if basics_data['tax_rate']:
                event.settings.tax_rate_default = event.tax_rules.create(
                    name=LazyI18nString.from_gettext(ugettext('VAT')),
                    rate=basics_data['tax_rate']
                )

            logdata = {}
            for f in form_list:
                logdata.update({
                    k: v for k, v in f.cleaned_data.items()
                })
            event.log_action('pretix.event.settings', user=self.request.user, data=logdata)

            if copy_data and copy_data['copy_from_event']:
                from_event = copy_data['copy_from_event']
                event.copy_data_from(from_event)

            event.settings.set('timezone', basics_data['timezone'])
            event.settings.set('locale', basics_data['locale'])
            event.settings.set('locales', foundation_data['locales'])

        return redirect(reverse('control:event.settings', kwargs={
            'organizer': event.organizer.slug,
            'event': event.slug,
        }) + '?congratulations=1')
Ejemplo n.º 23
0
def send_mails(event: Event,
               user: int,
               subject: dict,
               message: dict,
               orders: list,
               items: list,
               recipients: str,
               filter_checkins: bool,
               not_checked_in: bool,
               checkin_lists: list,
               attachments: list = None) -> None:
    failures = []
    user = User.objects.get(pk=user) if user else None
    orders = Order.objects.filter(pk__in=orders, event=event)
    subject = LazyI18nString(subject)
    message = LazyI18nString(message)

    for o in orders:
        send_to_order = recipients in ('both', 'orders')

        try:
            ia = o.invoice_address
        except InvoiceAddress.DoesNotExist:
            ia = InvoiceAddress(order=o)

        if recipients in ('both', 'attendees'):
            for p in o.positions.prefetch_related('addons'):
                if p.addon_to_id is not None:
                    continue

                if p.item_id not in items and not any(a.item_id in items
                                                      for a in p.addons.all()):
                    continue

                if filter_checkins:
                    checkins = list(p.checkins.all())
                    allowed = ((not_checked_in and not checkins)
                               or (any(c.list_id in checkin_lists
                                       for c in checkins)))
                    if not allowed:
                        continue

                if not p.attendee_email:
                    if recipients == 'attendees':
                        send_to_order = True
                    continue

                if p.attendee_email == o.email and send_to_order:
                    continue

                try:
                    with language(o.locale, event.settings.region):
                        email_context = get_email_context(
                            event=event,
                            order=o,
                            position_or_address=p,
                            position=p)
                        mail(p.attendee_email,
                             subject,
                             message,
                             email_context,
                             event,
                             locale=o.locale,
                             order=o,
                             position=p,
                             attach_cached_files=attachments)
                        o.log_action(
                            'pretix.plugins.sendmail.order.email.sent.attendee',
                            user=user,
                            data={
                                'position':
                                p.positionid,
                                'subject':
                                subject.localize(
                                    o.locale).format_map(email_context),
                                'message':
                                message.localize(
                                    o.locale).format_map(email_context),
                                'recipient':
                                p.attendee_email
                            })
                except SendMailException:
                    failures.append(p.attendee_email)

        if send_to_order and o.email:
            try:
                with language(o.locale, event.settings.region):
                    email_context = get_email_context(event=event,
                                                      order=o,
                                                      position_or_address=ia)
                    mail(o.email,
                         subject,
                         message,
                         email_context,
                         event,
                         locale=o.locale,
                         order=o,
                         attach_cached_files=attachments)
                    o.log_action('pretix.plugins.sendmail.order.email.sent',
                                 user=user,
                                 data={
                                     'subject':
                                     subject.localize(
                                         o.locale).format_map(email_context),
                                     'message':
                                     message.localize(
                                         o.locale).format_map(email_context),
                                     'recipient':
                                     o.email
                                 })
            except SendMailException:
                failures.append(o.email)
Ejemplo n.º 24
0
    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        kwargs.setdefault('initial', {})
        kwargs['initial'][
            'gift_card_expires'] = self.event.organizer.default_gift_card_expiry
        super().__init__(*args, **kwargs)
        self.fields['send_subject'] = I18nFormField(
            label=_("Subject"),
            required=True,
            widget_kwargs={'attrs': {
                'data-display-dependency': '#id_send'
            }},
            initial=_('Canceled: {event}'),
            widget=I18nTextInput,
            locales=self.event.settings.get('locales'),
        )
        self.fields['send_message'] = I18nFormField(
            label=_('Message'),
            widget=I18nTextarea,
            required=True,
            widget_kwargs={'attrs': {
                'data-display-dependency': '#id_send'
            }},
            locales=self.event.settings.get('locales'),
            initial=LazyI18nString.from_gettext(
                gettext_noop(
                    'Hello,\n\n'
                    'with this email, we regret to inform you that {event} has been canceled.\n\n'
                    'We will refund you {refund_amount} to your original payment method.\n\n'
                    'You can view the current state of your order here:\n\n{url}\n\nBest regards,\n\n'
                    'Your {event} team')))

        self._set_field_placeholders('send_subject', [
            'event_or_subevent', 'refund_amount', 'position_or_address',
            'order', 'event'
        ])
        self._set_field_placeholders('send_message', [
            'event_or_subevent', 'refund_amount', 'position_or_address',
            'order', 'event'
        ])
        self.fields['send_waitinglist_subject'] = I18nFormField(
            label=_("Subject"),
            required=True,
            initial=_('Canceled: {event}'),
            widget=I18nTextInput,
            widget_kwargs={
                'attrs': {
                    'data-display-dependency': '#id_send_waitinglist'
                }
            },
            locales=self.event.settings.get('locales'),
        )
        self.fields['send_waitinglist_message'] = I18nFormField(
            label=_('Message'),
            widget=I18nTextarea,
            required=True,
            locales=self.event.settings.get('locales'),
            widget_kwargs={
                'attrs': {
                    'data-display-dependency': '#id_send_waitinglist'
                }
            },
            initial=LazyI18nString.from_gettext(
                gettext_noop(
                    'Hello,\n\n'
                    'with this email, we regret to inform you that {event} has been canceled.\n\n'
                    'You will therefore not receive a ticket from the waiting list.\n\n'
                    'Best regards,\n\n'
                    'Your {event} team')))
        self._set_field_placeholders('send_waitinglist_subject',
                                     ['event_or_subevent', 'event'])
        self._set_field_placeholders('send_waitinglist_message',
                                     ['event_or_subevent', 'event'])

        if self.event.has_subevents:
            self.fields['subevent'].queryset = self.event.subevents.all()
            self.fields['subevent'].widget = Select2(
                attrs={
                    'data-inverse-dependency':
                    '#id_all_subevents',
                    'data-model-select2':
                    'event',
                    'data-select2-url':
                    reverse('control:event.subevents.select2',
                            kwargs={
                                'event': self.event.slug,
                                'organizer': self.event.organizer.slug,
                            }),
                    'data-placeholder':
                    pgettext_lazy('subevent', 'All dates')
                })
            self.fields['subevent'].widget.choices = self.fields[
                'subevent'].choices
        else:
            del self.fields['subevent']
            del self.fields['all_subevents']
        change_decimal_field(self.fields['keep_fee_fixed'],
                             self.event.currency)
Ejemplo n.º 25
0
def arrange(context):
    context.category_public = create_category(
        LazyI18nString({
            'ar': 'عام',
            'tr': 'Genel',
            'en': 'Public'
        }))
    context.alfam = create_dorm('Alfam', context.category_public)

    context.luxury_shower = create_room_feature(
        LazyI18nString({
            'ar': 'شاور فاخر',
            'tr': 'lüks duş',
            'en': 'Luxury Shower'
        }))

    context.room_type_options = [
        RadioOption(name=LazyI18nString({
            'ar': 'غرفة سنجل',
            'tr': 'tek oda',
            'en': 'Single'
        })),
        RadioOption(name=LazyI18nString({
            'ar': 'غرفة دبل',
            'tr': 'double oda',
            'en': 'Double'
        }))
    ]
    context.room_types = create_radio_filter(
        context.room_type_options,
        LazyI18nString({
            'ar': 'نوع الغرفة',
            'tr': 'oda tip',
            'en': 'Room Type'
        }))
    context.room_type_single_choice = create_radio_choice(
        context.room_type_options[0], context.room_types)
    context.room_type_double_choice = create_radio_choice(
        context.room_type_options[1], context.room_types)

    context.people_allowed_number_filter = IntegralFilter(
        name='People Allowed Number')
    context.people_allowed_number_filter.save()
    context.one_person = create_integral_choice(
        context.people_allowed_number_filter, 1)
    context.two_persons = create_integral_choice(
        context.people_allowed_number_filter, 2)

    context.meal_options = [
        RadioOption(name=LazyI18nString({
            'ar': 'افطار',
            'tr': 'Kahvalti',
            'en': 'Breakfast'
        })),
        RadioOption(name=LazyI18nString({
            'ar': 'عشاء',
            'tr': 'Akşam Yemeği',
            'en': 'Dinner'
        }))
    ]
    context.meals = create_radio_filter(context.meal_options,
                                        name=LazyI18nString({
                                            'ar': 'وجبة',
                                            'tr': 'Yemek',
                                            'en': 'Meals'
                                        }))
    context.meals_choice_breakfast = create_radio_choice(
        context.meal_options[0], context.meals)
    context.meals_choice_dinner = create_radio_choice(context.meal_options[1],
                                                      context.meals)

    context.price_filter = IntegralFilter(name=LazyI18nString({
        'ar': 'السعر',
        'tr': 'Fiyat',
        'en': 'Price'
    }))
    context.price_filter.save()
    context.price_1000 = create_integral_choice(context.price_filter, 1000)

    context.options_duration = [
        RadioOption(name=LazyI18nString({
            'ar': 'ربيع',
            'tr': 'Ilkbahar',
            'en': 'Spring'
        })),
        RadioOption(name=LazyI18nString({
            'ar': 'شتاء',
            'tr': 'Kış',
            'en': 'Winter'
        }))
    ]
    context.duration = create_radio_filter(
        context.options_duration,
        LazyI18nString({
            'ar': 'المدة',
            'tr': 'Müddet',
            'en': 'Duration'
        }))
    context.duration_choice_spring = create_radio_choice(
        context.options_duration[0], context.duration)
    context.duration_choice_winter = create_radio_choice(
        context.options_duration[1], context.duration)

    context.room1 = create_room_with_radio_integral_features(
        context.alfam, [
            context.meals_choice_dinner, context.room_type_single_choice,
            context.duration_choice_spring
        ], [context.price_1000, context.one_person], [])

    context.room2 = create_room_with_radio_integral_features(
        context.alfam, [
            context.meals_choice_breakfast, context.room_type_double_choice,
            context.duration_choice_winter
        ], [context.price_1000, context.two_persons], [
            context.luxury_shower,
        ])
Ejemplo n.º 26
0
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry,
                                   **kwargs):
    plains = {
        'pretix.event.comment':
        _('The event\'s internal comment has been updated.'),
        'pretix.event.order.modified':
        _('The order details have been changed.'),
        'pretix.event.order.unpaid':
        _('The order has been marked as unpaid.'),
        'pretix.event.order.secret.changed':
        _('The order\'s secret has been changed.'),
        'pretix.event.order.expirychanged':
        _('The order\'s expiry date has been changed.'),
        'pretix.event.order.expired':
        _('The order has been marked as expired.'),
        'pretix.event.order.paid':
        _('The order has been marked as paid.'),
        'pretix.event.order.refunded':
        _('The order has been refunded.'),
        'pretix.event.order.canceled':
        _('The order has been canceled.'),
        'pretix.event.order.deleted':
        _('The test mode order {code} has been deleted.'),
        'pretix.event.order.placed':
        _('The order has been created.'),
        'pretix.event.order.placed.require_approval':
        _('The order requires approval before it can continue to be processed.'
          ),
        'pretix.event.order.approved':
        _('The order has been approved.'),
        'pretix.event.order.denied':
        _('The order has been denied.'),
        'pretix.event.order.contact.changed':
        _('The email address has been changed from "{old_email}" '
          'to "{new_email}".'),
        'pretix.event.order.locale.changed':
        _('The order locale has been changed.'),
        'pretix.event.order.invoice.generated':
        _('The invoice has been generated.'),
        'pretix.event.order.invoice.regenerated':
        _('The invoice has been regenerated.'),
        'pretix.event.order.invoice.reissued':
        _('The invoice has been reissued.'),
        'pretix.event.order.comment':
        _('The order\'s internal comment has been updated.'),
        'pretix.event.order.checkin_attention':
        _('The order\'s flag to require attention at check-in has been '
          'toggled.'),
        'pretix.event.order.payment.changed':
        _('A new payment {local_id} has been started instead of the previous one.'
          ),
        'pretix.event.order.email.sent':
        _('An unidentified type email has been sent.'),
        'pretix.event.order.email.error':
        _('Sending of an email has failed.'),
        'pretix.event.order.email.attachments.skipped':
        _('The email has been sent without attachments since they '
          'would have been too large to be likely to arrive.'),
        'pretix.event.order.email.custom_sent':
        _('A custom email has been sent.'),
        'pretix.event.order.email.download_reminder_sent':
        _('An email has been sent with a reminder that the ticket '
          'is available for download.'),
        'pretix.event.order.email.expire_warning_sent':
        _('An email has been sent with a warning that the order is about '
          'to expire.'),
        'pretix.event.order.email.order_canceled':
        _('An email has been sent to notify the user that the order has been canceled.'
          ),
        'pretix.event.order.email.order_changed':
        _('An email has been sent to notify the user that the order has been changed.'
          ),
        'pretix.event.order.email.order_free':
        _('An email has been sent to notify the user that the order has been received.'
          ),
        'pretix.event.order.email.order_paid':
        _('An email has been sent to notify the user that payment has been received.'
          ),
        'pretix.event.order.email.order_denied':
        _('An email has been sent to notify the user that the order has been denied.'
          ),
        'pretix.event.order.email.order_approved':
        _('An email has been sent to notify the user that the order has '
          'been approved.'),
        'pretix.event.order.email.order_placed':
        _('An email has been sent to notify the user that the order has been received and requires payment.'
          ),
        'pretix.event.order.email.order_placed_require_approval':
        _('An email has been sent to notify the user that '
          'the order has been received and requires '
          'approval.'),
        'pretix.event.order.email.resend':
        _('An email with a link to the order detail page has been resent to the user.'
          ),
        'pretix.event.order.payment.confirmed':
        _('Payment {local_id} has been confirmed.'),
        'pretix.event.order.payment.canceled':
        _('Payment {local_id} has been canceled.'),
        'pretix.event.order.payment.started':
        _('Payment {local_id} has been started.'),
        'pretix.event.order.payment.failed':
        _('Payment {local_id} has failed.'),
        'pretix.event.order.quotaexceeded':
        _('The order could not be marked as paid: {message}'),
        'pretix.event.order.overpaid':
        _('The order has been overpaid.'),
        'pretix.event.order.refund.created':
        _('Refund {local_id} has been created.'),
        'pretix.event.order.refund.created.externally':
        _('Refund {local_id} has been created by an external entity.'),
        'pretix.event.order.refund.requested':
        _('The customer requested you to issue a refund.'),
        'pretix.event.order.refund.done':
        _('Refund {local_id} has been completed.'),
        'pretix.event.order.refund.canceled':
        _('Refund {local_id} has been canceled.'),
        'pretix.event.order.refund.failed':
        _('Refund {local_id} has failed.'),
        'pretix.control.auth.user.created':
        _('The user has been created.'),
        'pretix.user.settings.2fa.enabled':
        _('Two-factor authentication has been enabled.'),
        'pretix.user.settings.2fa.disabled':
        _('Two-factor authentication has been disabled.'),
        'pretix.user.settings.2fa.regenemergency':
        _('Your two-factor emergency codes have been regenerated.'),
        'pretix.user.settings.2fa.device.added':
        _('A new two-factor authentication device "{name}" has been added to '
          'your account.'),
        'pretix.user.settings.2fa.device.deleted':
        _('The two-factor authentication device "{name}" has been removed '
          'from your account.'),
        'pretix.user.settings.notifications.enabled':
        _('Notifications have been enabled.'),
        'pretix.user.settings.notifications.disabled':
        _('Notifications have been disabled.'),
        'pretix.user.settings.notifications.changed':
        _('Your notification settings have been changed.'),
        'pretix.user.anonymized':
        _('This user has been anonymized.'),
        'pretix.user.oauth.authorized':
        _('The application "{application_name}" has been authorized to access your '
          'account.'),
        'pretix.control.auth.user.forgot_password.mail_sent':
        _('Password reset mail sent.'),
        'pretix.control.auth.user.forgot_password.recovered':
        _('The password has been reset.'),
        'pretix.organizer.deleted':
        _('The organizer "{name}" has been deleted.'),
        'pretix.voucher.added':
        _('The voucher has been created.'),
        'pretix.voucher.added.waitinglist':
        _('The voucher has been created and sent to a person on the waiting list.'
          ),
        'pretix.voucher.changed':
        _('The voucher has been changed.'),
        'pretix.voucher.deleted':
        _('The voucher has been deleted.'),
        'pretix.voucher.redeemed':
        _('The voucher has been redeemed in order {order_code}.'),
        'pretix.event.item.added':
        _('The product has been created.'),
        'pretix.event.item.changed':
        _('The product has been changed.'),
        'pretix.event.item.deleted':
        _('The product has been deleted.'),
        'pretix.event.item.variation.added':
        _('The variation "{value}" has been created.'),
        'pretix.event.item.variation.deleted':
        _('The variation "{value}" has been deleted.'),
        'pretix.event.item.variation.changed':
        _('The variation "{value}" has been changed.'),
        'pretix.event.item.addons.added':
        _('An add-on has been added to this product.'),
        'pretix.event.item.addons.removed':
        _('An add-on has been removed from this product.'),
        'pretix.event.item.addons.changed':
        _('An add-on has been changed on this product.'),
        'pretix.event.item.bundles.added':
        _('A bundled item has been added to this product.'),
        'pretix.event.item.bundles.removed':
        _('A bundled item has been removed from this product.'),
        'pretix.event.item.bundles.changed':
        _('A bundled item has been changed on this product.'),
        'pretix.event.quota.added':
        _('The quota has been added.'),
        'pretix.event.quota.deleted':
        _('The quota has been deleted.'),
        'pretix.event.quota.changed':
        _('The quota has been changed.'),
        'pretix.event.category.added':
        _('The category has been added.'),
        'pretix.event.category.deleted':
        _('The category has been deleted.'),
        'pretix.event.category.changed':
        _('The category has been changed.'),
        'pretix.event.question.added':
        _('The question has been added.'),
        'pretix.event.question.deleted':
        _('The question has been deleted.'),
        'pretix.event.question.changed':
        _('The question has been changed.'),
        'pretix.event.taxrule.added':
        _('The tax rule has been added.'),
        'pretix.event.taxrule.deleted':
        _('The tax rule has been deleted.'),
        'pretix.event.taxrule.changed':
        _('The tax rule has been changed.'),
        'pretix.event.checkinlist.added':
        _('The check-in list has been added.'),
        'pretix.event.checkinlist.deleted':
        _('The check-in list has been deleted.'),
        'pretix.event.checkinlist.changed':
        _('The check-in list has been changed.'),
        'pretix.event.settings':
        _('The event settings have been changed.'),
        'pretix.event.tickets.settings':
        _('The ticket download settings have been changed.'),
        'pretix.event.plugins.enabled':
        _('A plugin has been enabled.'),
        'pretix.event.plugins.disabled':
        _('A plugin has been disabled.'),
        'pretix.event.live.activated':
        _('The shop has been taken live.'),
        'pretix.event.live.deactivated':
        _('The shop has been taken offline.'),
        'pretix.event.testmode.activated':
        _('The shop has been taken into test mode.'),
        'pretix.event.testmode.deactivated':
        _('The test mode has been disabled.'),
        'pretix.event.added':
        _('The event has been created.'),
        'pretix.event.changed':
        _('The event settings have been changed.'),
        'pretix.event.question.option.added':
        _('An answer option has been added to the question.'),
        'pretix.event.question.option.deleted':
        _('An answer option has been removed from the question.'),
        'pretix.event.question.option.changed':
        _('An answer option has been changed.'),
        'pretix.event.permissions.added':
        _('A user has been added to the event team.'),
        'pretix.event.permissions.invited':
        _('A user has been invited to the event team.'),
        'pretix.event.permissions.changed':
        _('A user\'s permissions have been changed.'),
        'pretix.event.permissions.deleted':
        _('A user has been removed from the event team.'),
        'pretix.waitinglist.voucher':
        _('A voucher has been sent to a person on the waiting list.'),
        'pretix.event.orders.waitinglist.deleted':
        _('An entry has been removed from the waiting list.'),
        'pretix.event.orders.waitinglist.changed':
        _('An entry has been changed on the waiting list.'),
        'pretix.event.orders.waitinglist.added':
        _('An entry has been added to the waiting list.'),
        'pretix.team.created':
        _('The team has been created.'),
        'pretix.team.changed':
        _('The team settings have been changed.'),
        'pretix.team.deleted':
        _('The team has been deleted.'),
        'pretix.subevent.deleted':
        pgettext_lazy('subevent', 'The event date has been deleted.'),
        'pretix.subevent.changed':
        pgettext_lazy('subevent', 'The event date has been changed.'),
        'pretix.subevent.added':
        pgettext_lazy('subevent', 'The event date has been created.'),
        'pretix.subevent.quota.added':
        pgettext_lazy('subevent', 'A quota has been added to the event date.'),
        'pretix.subevent.quota.changed':
        pgettext_lazy('subevent',
                      'A quota has been changed on the event date.'),
        'pretix.subevent.quota.deleted':
        pgettext_lazy('subevent',
                      'A quota has been removed from the event date.'),
        'pretix.device.created':
        _('The device has been created.'),
        'pretix.device.changed':
        _('The device has been changed.'),
        'pretix.device.revoked':
        _('Access of the device has been revoked.'),
        'pretix.device.initialized':
        _('The device has been initialized.'),
        'pretix.device.keyroll':
        _('The access token of the device has been regenerated.'),
        'pretix.device.updated':
        _('The device has notified the server of an hardware or software update.'
          ),
    }

    data = json.loads(logentry.data)

    if logentry.action_type.startswith('pretix.event.item.variation'):
        if 'value' not in data:
            # Backwards compatibility
            var = ItemVariation.objects.filter(id=data['id']).first()
            if var:
                data['value'] = str(var.value)
            else:
                data['value'] = '?'
        else:
            data['value'] = LazyI18nString(data['value'])

    if logentry.action_type in plains:
        data = defaultdict(lambda: '?', data)
        return plains[logentry.action_type].format_map(data)

    if logentry.action_type.startswith('pretix.event.order.changed'):
        return _display_order_changed(sender, logentry)

    if logentry.action_type.startswith('pretix.event.payment.provider.'):
        return _('The settings of a payment provider have been changed.')

    if logentry.action_type.startswith('pretix.event.tickets.provider.'):
        return _('The settings of a ticket output provider have been changed.')

    if logentry.action_type == 'pretix.event.order.consent':
        return _('The user confirmed the following message: "{}"').format(
            bleach.clean(logentry.parsed_data.get('msg'), tags=[], strip=True))

    if logentry.action_type == 'pretix.event.checkin':
        return _display_checkin(sender, logentry)

    if logentry.action_type == 'pretix.control.views.checkin':
        # deprecated
        dt = dateutil.parser.parse(data.get('datetime'))
        tz = pytz.timezone(sender.settings.timezone)
        dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
        if 'list' in data:
            try:
                checkin_list = sender.checkin_lists.get(
                    pk=data.get('list')).name
            except CheckinList.DoesNotExist:
                checkin_list = _("(unknown)")
        else:
            checkin_list = _("(unknown)")

        if data.get('first'):
            return _(
                'Position #{posid} has been checked in manually at {datetime} on list "{list}".'
            ).format(
                posid=data.get('positionid'),
                datetime=dt_formatted,
                list=checkin_list,
            )
        return _(
            'Position #{posid} has been checked in again at {datetime} on list "{list}".'
        ).format(posid=data.get('positionid'),
                 datetime=dt_formatted,
                 list=checkin_list)

    if logentry.action_type in ('pretix.control.views.checkin.reverted',
                                'pretix.event.checkin.reverted'):
        if 'list' in data:
            try:
                checkin_list = sender.checkin_lists.get(
                    pk=data.get('list')).name
            except CheckinList.DoesNotExist:
                checkin_list = _("(unknown)")
        else:
            checkin_list = _("(unknown)")

        return _(
            'The check-in of position #{posid} on list "{list}" has been reverted.'
        ).format(
            posid=data.get('positionid'),
            list=checkin_list,
        )

    if logentry.action_type == 'pretix.team.member.added':
        return _('{user} has been added to the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.removed':
        return _('{user} has been removed from the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.joined':
        return _('{user} has joined the team using the invite sent to {email}.'
                 ).format(user=data.get('email'),
                          email=data.get('invite_email'))

    if logentry.action_type == 'pretix.team.invite.created':
        return _('{user} has been invited to the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.invite.resent':
        return _('Invite for {user} has been resent.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.invite.deleted':
        return _('The invite for {user} has been revoked.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.token.created':
        return _('The token "{name}" has been created.').format(
            name=data.get('name'))

    if logentry.action_type == 'pretix.team.token.deleted':
        return _('The token "{name}" has been revoked.').format(
            name=data.get('name'))

    if logentry.action_type == 'pretix.user.settings.changed':
        text = str(_('Your account settings have been changed.'))
        if 'email' in data:
            text = text + ' ' + str(
                _('Your email address has been changed to {email}.').format(
                    email=data['email']))
        if 'new_pw' in data:
            text = text + ' ' + str(_('Your password has been changed.'))
        if data.get('is_active') is True:
            text = text + ' ' + str(_('Your account has been enabled.'))
        elif data.get('is_active') is False:
            text = text + ' ' + str(_('Your account has been disabled.'))
        return text

    if logentry.action_type == 'pretix.control.auth.user.impersonated':
        return str(_('You impersonated {}.')).format(data['other_email'])

    if logentry.action_type == 'pretix.control.auth.user.impersonate_stopped':
        return str(_('You stopped impersonating {}.')).format(
            data['other_email'])
Ejemplo n.º 27
0
 def get_initial(self):
     return {'name': LazyI18nString.from_gettext(ugettext('VAT'))}
Ejemplo n.º 28
0
def i18n_unserialise(value):
    try:
        return LazyI18nString(json.loads(value))
    except ValueError:
        return LazyI18nString(str(value))
Ejemplo n.º 29
0
 def test_serialize_lazyi18nstring(self):
     self._test_serialization(
         LazyI18nString({
             'de': 'Hallo',
             'en': 'Hello'
         }), LazyI18nString)
Ejemplo n.º 30
0
def i18n_uns(v):
    try:
        return LazyI18nString(json.loads(v))
    except ValueError:
        return LazyI18nString(str(v))
Ejemplo n.º 31
0
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
    plains = {
        'pretix.event.comment': _('The event\'s internal comment has been updated.'),
        'pretix.event.order.modified': _('The order details have been modified.'),
        'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
        'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
        'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
        'pretix.event.order.expired': _('The order has been marked as expired.'),
        'pretix.event.order.paid': _('The order has been marked as paid.'),
        'pretix.event.order.refunded': _('The order has been refunded.'),
        'pretix.event.order.canceled': _('The order has been canceled.'),
        'pretix.event.order.placed': _('The order has been created.'),
        'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
                                                'to "{new_email}".'),
        'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
        'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
        'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
        'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
        'pretix.event.order.payment.changed': _('The payment method has been changed.'),
        'pretix.event.order.email.sent': _('An unindentified type email has been sent.'),
        'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
        'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
                                                          'to expire.'),
        'pretix.event.order.email.order_canceled': _('An email has been sent to notify user order has been canceled.'),
        'pretix.event.order.email.order_changed': _('An email has been sent to notify user order has been changed.'),
        'pretix.event.order.email.order_free': _('An email has been sent to notify user order has been received.'),
        'pretix.event.order.email.order_paid': _('An email has been sent to notify user payment has been received.'),
        'pretix.event.order.email.order_placed': _('An email has been sent to notify user order has been received and require payment.'),
        'pretix.event.order.email.resend': _('An email has been sent with link to the order detail page has been resent to the user.'),
        'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
        'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
        'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
        'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
                                                   'your account.'),
        'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
                                                     'from your account.'),
        'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
        'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
        'pretix.voucher.added': _('The voucher has been created.'),
        'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
        'pretix.voucher.changed': _('The voucher has been modified.'),
        'pretix.voucher.deleted': _('The voucher has been deleted.'),
        'pretix.voucher.redeemed': _('The voucher has been redeemed in order {order_code}.'),
        'pretix.event.item.added': _('The product has been created.'),
        'pretix.event.item.changed': _('The product has been modified.'),
        'pretix.event.item.deleted': _('The product has been deleted.'),
        'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
        'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
        'pretix.event.item.variation.changed': _('The variation "{value}" has been modified.'),
        'pretix.event.item.addons.added': _('An add-on has been added to this product.'),
        'pretix.event.item.addons.removed': _('An add-on has been removed from this product.'),
        'pretix.event.item.addons.changed': _('An add-on has been changed on this product.'),
        'pretix.event.quota.added': _('The quota has been added.'),
        'pretix.event.quota.deleted': _('The quota has been deleted.'),
        'pretix.event.quota.changed': _('The quota has been modified.'),
        'pretix.event.category.added': _('The category has been added.'),
        'pretix.event.category.deleted': _('The category has been deleted.'),
        'pretix.event.category.changed': _('The category has been modified.'),
        'pretix.event.question.added': _('The question has been added.'),
        'pretix.event.question.deleted': _('The question has been deleted.'),
        'pretix.event.question.changed': _('The question has been modified.'),
        'pretix.event.settings': _('The event settings have been changed.'),
        'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
        'pretix.event.plugins.enabled': _('A plugin has been enabled.'),
        'pretix.event.plugins.disabled': _('A plugin has been disabled.'),
        'pretix.event.live.activated': _('The shop has been taken live.'),
        'pretix.event.live.deactivated': _('The shop has been taken offline.'),
        'pretix.event.changed': _('The event settings have been changed.'),
        'pretix.event.question.option.added': _('An answer option has been added to the question.'),
        'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
        'pretix.event.question.option.changed': _('An answer option has been changed.'),
        'pretix.event.permissions.added': _('A user has been added to the event team.'),
        'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
        'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
        'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
        'pretix.waitinglist.voucher': _('A voucher has been sent to a person on the waiting list.'),
        'pretix.team.created': _('The team has been created.'),
        'pretix.team.changed': _('The team settings have been modified.'),
        'pretix.team.deleted': _('The team has been deleted.'),
        'pretix.subevent.deleted': pgettext_lazy('subevent', 'The event date has been deleted.'),
        'pretix.subevent.changed': pgettext_lazy('subevent', 'The event date has been modified.'),
        'pretix.subevent.added': pgettext_lazy('subevent', 'The event date has been created.'),
        'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
        'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been modified on the event date.'),
        'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
    }

    data = json.loads(logentry.data)

    if logentry.action_type.startswith('pretix.event.item.variation'):
        if 'value' not in data:
            # Backwards compatibility
            var = ItemVariation.objects.filter(id=data['id']).first()
            if var:
                data['value'] = str(var.value)
            else:
                data['value'] = '?'
        else:
            data['value'] = LazyI18nString(data['value'])

    if logentry.action_type in plains:
        return plains[logentry.action_type].format_map(data)

    if logentry.action_type.startswith('pretix.event.order.changed'):
        return _display_order_changed(sender, logentry)

    if logentry.action_type.startswith('pretix.event.payment.provider.'):
        return _('The settings of a payment provider have been changed.')

    if logentry.action_type.startswith('pretix.event.tickets.provider.'):
        return _('The settings of a ticket output provider have been changed.')

    if logentry.action_type == 'pretix.team.member.added':
        return _('{user} has been added to the team.').format(user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.removed':
        return _('{user} has been removed from the team.').format(user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.joined':
        return _('{user} has joined the team using the invite sent to {email}.').format(
            user=data.get('email'), email=data.get('invite_email')
        )

    if logentry.action_type == 'pretix.team.invite.created':
        return _('{user} has been invited to the team.').format(user=data.get('email'))

    if logentry.action_type == 'pretix.team.invite.deleted':
        return _('The invite for {user} has been revoked.').format(user=data.get('email'))

    if logentry.action_type == 'pretix.team.token.created':
        return _('The token "{name}" has been created.').format(name=data.get('name'))

    if logentry.action_type == 'pretix.team.token.deleted':
        return _('The token "{name}" has been revoked.').format(name=data.get('name'))

    if logentry.action_type == 'pretix.user.settings.changed':
        text = str(_('Your account settings have been changed.'))
        if 'email' in data:
            text = text + ' ' + str(_('Your email address has been changed to {email}.').format(email=data['email']))
        if 'new_pw' in data:
            text = text + ' ' + str(_('Your password has been changed.'))
        return text
Ejemplo n.º 32
0
    },
    'mail_from': {
        'default': settings.MAIL_FROM,
        'type': str
    },
    'mail_text_signature': {
        'type': LazyI18nString,
        'default': ""
    },
    'mail_text_resend_link': {
        'type': LazyI18nString,
        'default': LazyI18nString.from_gettext(ugettext_noop("""Hello,

you receive this message because you asked us to send you the link
to your order for {event}.

You can change your order details and view the status of your order at
{url}

Best regards,
Your {event} team"""))
    },
    'mail_text_resend_all_links': {
        'type': LazyI18nString,
        'default': LazyI18nString.from_gettext(ugettext_noop("""Hello,

somebody requested a list of your orders for {event}.
The list is as follows:

{orders}

Best regards,
Ejemplo n.º 33
0
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry,
                                   **kwargs):
    plains = {
        'pretix.event.comment':
        _('The event\'s internal comment has been updated.'),
        'pretix.event.order.modified':
        _('The order details have been changed.'),
        'pretix.event.order.unpaid':
        _('The order has been marked as unpaid.'),
        'pretix.event.order.secret.changed':
        _('The order\'s secret has been changed.'),
        'pretix.event.order.expirychanged':
        _('The order\'s expiry date has been changed.'),
        'pretix.event.order.expired':
        _('The order has been marked as expired.'),
        'pretix.event.order.paid':
        _('The order has been marked as paid.'),
        'pretix.event.order.refunded':
        _('The order has been refunded.'),
        'pretix.event.order.canceled':
        _('The order has been canceled.'),
        'pretix.event.order.placed':
        _('The order has been created.'),
        'pretix.event.order.contact.changed':
        _('The email address has been changed from "{old_email}" '
          'to "{new_email}".'),
        'pretix.event.order.locale.changed':
        _('The order locale has been changed.'),
        'pretix.event.order.invoice.generated':
        _('The invoice has been generated.'),
        'pretix.event.order.invoice.regenerated':
        _('The invoice has been regenerated.'),
        'pretix.event.order.invoice.reissued':
        _('The invoice has been reissued.'),
        'pretix.event.order.comment':
        _('The order\'s internal comment has been updated.'),
        'pretix.event.order.checkin_attention':
        _('The order\'s flag to require attention at check-in has been '
          'toggled.'),
        'pretix.event.order.payment.changed':
        _('The payment method has been changed.'),
        'pretix.event.order.email.sent':
        _('An unidentified type email has been sent.'),
        'pretix.event.order.email.custom_sent':
        _('A custom email has been sent.'),
        'pretix.event.order.email.download_reminder_sent':
        _('An email has been sent with a reminder that the ticket '
          'is available for download.'),
        'pretix.event.order.email.expire_warning_sent':
        _('An email has been sent with a warning that the order is about '
          'to expire.'),
        'pretix.event.order.email.order_canceled':
        _('An email has been sent to notify the user that the order has been canceled.'
          ),
        'pretix.event.order.email.order_changed':
        _('An email has been sent to notify the user that the order has been changed.'
          ),
        'pretix.event.order.email.order_free':
        _('An email has been sent to notify the user that the order has been received.'
          ),
        'pretix.event.order.email.order_paid':
        _('An email has been sent to notify the user that payment has been received.'
          ),
        'pretix.event.order.email.order_placed':
        _('An email has been sent to notify the user that the order has been received and requires payment.'
          ),
        'pretix.event.order.email.resend':
        _('An email with a link to the order detail page has been resent to the user.'
          ),
        'pretix.control.auth.user.created':
        _('The user has been created.'),
        'pretix.user.settings.2fa.enabled':
        _('Two-factor authentication has been enabled.'),
        'pretix.user.settings.2fa.disabled':
        _('Two-factor authentication has been disabled.'),
        'pretix.user.settings.2fa.regenemergency':
        _('Your two-factor emergency codes have been regenerated.'),
        'pretix.user.settings.2fa.device.added':
        _('A new two-factor authentication device "{name}" has been added to '
          'your account.'),
        'pretix.user.settings.2fa.device.deleted':
        _('The two-factor authentication device "{name}" has been removed '
          'from your account.'),
        'pretix.user.settings.notifications.enabled':
        _('Notifications have been enabled.'),
        'pretix.user.settings.notifications.disabled':
        _('Notifications have been disabled.'),
        'pretix.user.settings.notifications.changed':
        _('Your notification settings have been changed.'),
        'pretix.control.auth.user.forgot_password.mail_sent':
        _('Password reset mail sent.'),
        'pretix.control.auth.user.forgot_password.recovered':
        _('The password has been reset.'),
        'pretix.voucher.added':
        _('The voucher has been created.'),
        'pretix.voucher.added.waitinglist':
        _('The voucher has been created and sent to a person on the waiting list.'
          ),
        'pretix.voucher.changed':
        _('The voucher has been changed.'),
        'pretix.voucher.deleted':
        _('The voucher has been deleted.'),
        'pretix.voucher.redeemed':
        _('The voucher has been redeemed in order {order_code}.'),
        'pretix.event.item.added':
        _('The product has been created.'),
        'pretix.event.item.changed':
        _('The product has been changed.'),
        'pretix.event.item.deleted':
        _('The product has been deleted.'),
        'pretix.event.item.variation.added':
        _('The variation "{value}" has been created.'),
        'pretix.event.item.variation.deleted':
        _('The variation "{value}" has been deleted.'),
        'pretix.event.item.variation.changed':
        _('The variation "{value}" has been changed.'),
        'pretix.event.item.addons.added':
        _('An add-on has been added to this product.'),
        'pretix.event.item.addons.removed':
        _('An add-on has been removed from this product.'),
        'pretix.event.item.addons.changed':
        _('An add-on has been changed on this product.'),
        'pretix.event.quota.added':
        _('The quota has been added.'),
        'pretix.event.quota.deleted':
        _('The quota has been deleted.'),
        'pretix.event.quota.changed':
        _('The quota has been changed.'),
        'pretix.event.category.added':
        _('The category has been added.'),
        'pretix.event.category.deleted':
        _('The category has been deleted.'),
        'pretix.event.category.changed':
        _('The category has been changed.'),
        'pretix.event.question.added':
        _('The question has been added.'),
        'pretix.event.question.deleted':
        _('The question has been deleted.'),
        'pretix.event.question.changed':
        _('The question has been changed.'),
        'pretix.event.taxrule.added':
        _('The tax rule has been added.'),
        'pretix.event.taxrule.deleted':
        _('The tax rule has been deleted.'),
        'pretix.event.taxrule.changed':
        _('The tax rule has been changed.'),
        'pretix.event.checkinlist.added':
        _('The check-in list has been added.'),
        'pretix.event.checkinlist.deleted':
        _('The check-in list has been deleted.'),
        'pretix.event.checkinlist.changed':
        _('The check-in list has been changed.'),
        'pretix.event.settings':
        _('The event settings have been changed.'),
        'pretix.event.tickets.settings':
        _('The ticket download settings have been changed.'),
        'pretix.event.plugins.enabled':
        _('A plugin has been enabled.'),
        'pretix.event.plugins.disabled':
        _('A plugin has been disabled.'),
        'pretix.event.live.activated':
        _('The shop has been taken live.'),
        'pretix.event.live.deactivated':
        _('The shop has been taken offline.'),
        'pretix.event.added':
        _('The event has been created.'),
        'pretix.event.changed':
        _('The event settings have been changed.'),
        'pretix.event.question.option.added':
        _('An answer option has been added to the question.'),
        'pretix.event.question.option.deleted':
        _('An answer option has been removed from the question.'),
        'pretix.event.question.option.changed':
        _('An answer option has been changed.'),
        'pretix.event.permissions.added':
        _('A user has been added to the event team.'),
        'pretix.event.permissions.invited':
        _('A user has been invited to the event team.'),
        'pretix.event.permissions.changed':
        _('A user\'s permissions have been changed.'),
        'pretix.event.permissions.deleted':
        _('A user has been removed from the event team.'),
        'pretix.waitinglist.voucher':
        _('A voucher has been sent to a person on the waiting list.'),
        'pretix.team.created':
        _('The team has been created.'),
        'pretix.team.changed':
        _('The team settings have been changed.'),
        'pretix.team.deleted':
        _('The team has been deleted.'),
        'pretix.subevent.deleted':
        pgettext_lazy('subevent', 'The event date has been deleted.'),
        'pretix.subevent.changed':
        pgettext_lazy('subevent', 'The event date has been changed.'),
        'pretix.subevent.added':
        pgettext_lazy('subevent', 'The event date has been created.'),
        'pretix.subevent.quota.added':
        pgettext_lazy('subevent', 'A quota has been added to the event date.'),
        'pretix.subevent.quota.changed':
        pgettext_lazy('subevent',
                      'A quota has been changed on the event date.'),
        'pretix.subevent.quota.deleted':
        pgettext_lazy('subevent',
                      'A quota has been removed from the event date.'),
    }

    data = json.loads(logentry.data)

    if logentry.action_type.startswith('pretix.event.item.variation'):
        if 'value' not in data:
            # Backwards compatibility
            var = ItemVariation.objects.filter(id=data['id']).first()
            if var:
                data['value'] = str(var.value)
            else:
                data['value'] = '?'
        else:
            data['value'] = LazyI18nString(data['value'])

    if logentry.action_type in plains:
        return plains[logentry.action_type].format_map(data)

    if logentry.action_type.startswith('pretix.event.order.changed'):
        return _display_order_changed(sender, logentry)

    if logentry.action_type.startswith('pretix.event.payment.provider.'):
        return _('The settings of a payment provider have been changed.')

    if logentry.action_type.startswith('pretix.event.tickets.provider.'):
        return _('The settings of a ticket output provider have been changed.')

    if logentry.action_type == 'pretix.event.checkin':
        return _display_checkin(sender, logentry)

    if logentry.action_type == 'pretix.control.views.checkin':
        dt = dateutil.parser.parse(data.get('datetime'))
        tz = pytz.timezone(sender.settings.timezone)
        dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
        if 'list' in data:
            try:
                checkin_list = sender.checkin_lists.get(
                    pk=data.get('list')).name
            except CheckinList.DoesNotExist:
                checkin_list = _("(unknown)")
        else:
            checkin_list = _("(unknown)")

        if data.get('first'):
            return _(
                'Position #{posid} has been checked in manually at {datetime} on list "{list}".'
            ).format(
                posid=data.get('positionid'),
                datetime=dt_formatted,
                list=checkin_list,
            )
        return _(
            'Position #{posid} has been checked in again at {datetime} on list "{list}".'
        ).format(posid=data.get('positionid'),
                 datetime=dt_formatted,
                 list=checkin_list)

    if logentry.action_type == 'pretix.team.member.added':
        return _('{user} has been added to the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.removed':
        return _('{user} has been removed from the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.member.joined':
        return _('{user} has joined the team using the invite sent to {email}.'
                 ).format(user=data.get('email'),
                          email=data.get('invite_email'))

    if logentry.action_type == 'pretix.team.invite.created':
        return _('{user} has been invited to the team.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.invite.deleted':
        return _('The invite for {user} has been revoked.').format(
            user=data.get('email'))

    if logentry.action_type == 'pretix.team.token.created':
        return _('The token "{name}" has been created.').format(
            name=data.get('name'))

    if logentry.action_type == 'pretix.team.token.deleted':
        return _('The token "{name}" has been revoked.').format(
            name=data.get('name'))

    if logentry.action_type == 'pretix.user.settings.changed':
        text = str(_('Your account settings have been changed.'))
        if 'email' in data:
            text = text + ' ' + str(
                _('Your email address has been changed to {email}.').format(
                    email=data['email']))
        if 'new_pw' in data:
            text = text + ' ' + str(_('Your password has been changed.'))
        if data.get('is_active') is True:
            text = text + ' ' + str(_('Your account has been enabled.'))
        elif data.get('is_active') is False:
            text = text + ' ' + str(_('Your account has been disabled.'))
        return text

    if logentry.action_type == 'pretix.control.auth.user.impersonated':
        return str(_('You impersonated {}.')).format(data['other_email'])

    if logentry.action_type == 'pretix.control.auth.user.impersonate_stopped':
        return str(_('You stopped impersonating {}.')).format(
            data['other_email'])