Ejemplo n.º 1
0
def retry(request, order):
    try:
        order = Order.objects.current.get(
            user=request.user,
            code=order,
        )
    except Order.DoesNotExist:
        return  # TODO: Handle this

    provider = Paypal(order.event)
    provider.init_api()

    if 'token' in request.GET:
        if 'PayerID' in request.GET:
            payment = paypalrestsdk.Payment.find(request.session.get('payment_paypal_id'))
            provider._execute_payment(payment, request, order)
        else:
            messages.error(request, _('It looks like you cancelled the PayPal payment'))
    else:
        payment = paypalrestsdk.Payment({
            'intent': 'sale',
            'payer': {
                "payment_method": "paypal",
            },
            "redirect_urls": {
                "return_url": build_absolute_uri('plugins:paypal:retry', kwargs={
                    'order': order.code
                }),
                "cancel_url": build_absolute_uri('plugins:paypal:retry', kwargs={
                    'order': order.code
                }),
            },
            "transactions": [
                {
                    "item_list": {
                        "items": [
                            {
                                "name": 'Order %s' % order.code,
                                "quantity": 1,
                                "price": str(order.total),
                                "currency": order.event.currency
                            }
                        ]
                    },
                    "amount": {
                        "currency": order.event.currency,
                        "total": str(order.total)
                    },
                    "description": __('Event tickets for %s') % order.event.name
                }
            ]
        })
        resp = provider._create_payment(request, payment)
        if resp:
            return redirect(resp)

    return redirect(eventreverse(order.event, 'presale:event.order', kwargs={
        'order': order.code,
        'secret': order.secret
    }) + '?paid=yes')
Ejemplo n.º 2
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        url = build_absolute_uri('plugins:pretixdroid:api.redeem',
                                 kwargs={
                                     'organizer':
                                     self.request.event.organizer.slug,
                                     'event': self.request.event.slug
                                 })
        if self.object.subevent:
            url = build_absolute_uri('plugins:pretixdroid:api.redeem',
                                     kwargs={
                                         'organizer':
                                         self.request.event.organizer.slug,
                                         'event':
                                         self.request.event.slug,
                                         'subevent':
                                         self.object.subevent.pk
                                     })

        data = {
            'version': API_VERSION,
            'url': url[:-7],  # the slice removes the redeem/ part at the end
            'key': self.object.key,
            'allow_search': self.object.allow_search,
            'show_info': self.object.show_info
        }
        ctx['config'] = self.object
        ctx['query'] = urllib.parse.urlencode(data, safe=':/')
        ctx['qrdata'] = json.dumps(data)
        return ctx
Ejemplo n.º 3
0
def send_notification_mail(notification: Notification, user: User):
    ctx = {
        'site': settings.PRETIX_INSTANCE_NAME,
        'site_url': settings.SITE_URL,
        'color': '#8E44B3',
        'notification': notification,
        'settings_url': build_absolute_uri(
            'control:user.settings.notifications',
        ),
        'disable_url': build_absolute_uri(
            'control:user.settings.notifications.off',
            kwargs={
                'token': user.notifications_token,
                'id': user.pk
            }
        )
    }

    tpl_html = get_template('pretixbase/email/notification.html')
    body_html = inline_css(tpl_html.render(ctx))
    tpl_plain = get_template('pretixbase/email/notification.txt')
    body_plain = tpl_plain.render(ctx)

    mail_send_task.apply_async(kwargs={
        'to': [user.email],
        'subject': '[{}] {}: {}'.format(
            settings.PRETIX_INSTANCE_NAME,
            notification.event.settings.mail_prefix or notification.event.slug.upper(),
            notification.title
        ),
        'body': body_plain,
        'html': body_html,
        'sender': settings.MAIL_FROM,
        'headers': {},
    })
Ejemplo n.º 4
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        key = self.request.event.settings.get('pretixdroid_key')
        if not key or 'flush_key' in self.request.GET:
            key = get_random_string(length=32,
                                    allowed_chars=string.ascii_uppercase + string.ascii_lowercase + string.digits)
            self.request.event.settings.set('pretixdroid_key', key)

        subevent = None
        url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })
        if self.request.event.has_subevents:
            if self.request.GET.get('subevent'):
                subevent = get_object_or_404(SubEvent, event=self.request.event, pk=self.request.GET['subevent'])
                url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
                    'organizer': self.request.event.organizer.slug,
                    'event': self.request.event.slug,
                    'subevent': subevent.pk
                })

        ctx['subevent'] = subevent

        ctx['qrdata'] = json.dumps({
            'version': API_VERSION,
            'url': url[:-7],  # the slice removes the redeem/ part at the end
            'key': key,
        })
        return ctx
Ejemplo n.º 5
0
def retry(request, order):
    try:
        order = Order.objects.current.get(user=request.user, code=order)
    except Order.DoesNotExist:
        return  # TODO: Handle this

    provider = Paypal(order.event)
    provider.init_api()

    if "token" in request.GET:
        if "PayerID" in request.GET:
            payment = paypalrestsdk.Payment.find(request.session.get("payment_paypal_id"))
            provider._execute_payment(payment, request, order)
        else:
            messages.error(request, _("It looks like you cancelled the PayPal payment"))
    else:
        payment = paypalrestsdk.Payment(
            {
                "intent": "sale",
                "payer": {"payment_method": "paypal"},
                "redirect_urls": {
                    "return_url": build_absolute_uri("plugins:paypal:retry", kwargs={"order": order.code}),
                    "cancel_url": build_absolute_uri("plugins:paypal:retry", kwargs={"order": order.code}),
                },
                "transactions": [
                    {
                        "item_list": {
                            "items": [
                                {
                                    "name": "Order %s" % order.code,
                                    "quantity": 1,
                                    "price": str(order.total),
                                    "currency": order.event.currency,
                                }
                            ]
                        },
                        "amount": {"currency": order.event.currency, "total": str(order.total)},
                        "description": __("Event tickets for %s") % order.event.name,
                    }
                ],
            }
        )
        resp = provider._create_payment(request, payment)
        if resp:
            return redirect(resp)

    return redirect(
        "presale:event.order", event=order.event.slug, organizer=order.event.organizer.slug, order=order.code
    )
Ejemplo n.º 6
0
    def post(self, request, *args, **kwargs):
        if self.form.is_valid():
            user = self.form.cleaned_data['user']

            if settings.HAS_REDIS:
                from django_redis import get_redis_connection
                rc = get_redis_connection("redis")
                if rc.exists('pretix_pwreset_%s' % (user.id)):
                    user.log_action('pretix.control.auth.user.forgot_password.denied.repeated')
                    messages.error(request, _('We already sent you an email in the last 24 hours.'))
                    return redirect('control:auth.forgot')
                else:
                    rc.setex('pretix_pwreset_%s' % (user.id), 3600 * 24, '1')

            try:
                mail(
                    user.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
                    {
                        'user': user,
                        'url': (build_absolute_uri('control:auth.forgot.recover')
                                + '?id=%d&token=%s' % (user.id, default_token_generator.make_token(user)))
                    },
                    None, locale=user.locale
                )
            except SendMailException:
                messages.error(request, _('There was an error sending the mail. Please try again later.'))
                return self.get(request, *args, **kwargs)

            user.log_action('pretix.control.auth.user.forgot_password.mail_sent')
            messages.success(request, _('We sent you an e-mail containing further instructions.'))
            return redirect('control:auth.forgot')
        else:
            return self.get(request, *args, **kwargs)
Ejemplo n.º 7
0
 def post(self, request, *args, **kwargs):
     if self.form.is_valid():
         user = self.form.cleaned_data["user"]
         if user.email:
             mail(
                 user,
                 _("Password recovery"),
                 "pretixpresale/email/forgot.txt",
                 {
                     "user": user,
                     "event": self.request.event,
                     "url": build_absolute_uri(
                         "presale:event.forgot.recover",
                         kwargs={"event": self.request.event.slug, "organizer": self.request.event.organizer.slug},
                     )
                     + "?token="
                     + self.generate_token(user),
                 },
                 self.request.event,
             )
             messages.success(request, _("We sent you an e-mail containing further instructions."))
         else:
             messages.success(
                 request,
                 _(
                     "We are unable to send you a new password, as you did not enter an e-mail "
                     "address at your registration."
                 ),
             )
         return redirect(
             "presale:event.forgot", organizer=self.request.event.organizer.slug, event=self.request.event.slug
         )
     else:
         return self.get(request, *args, **kwargs)
Ejemplo n.º 8
0
    def authentication_url(self, request):
        """
        This method will be called to populate the URL for the authentication method's tab on the login page.
        """

        redirect_uri = build_absolute_uri('plugins:pretix_oidc:oidc.response')

        client_id = config.get('pretix_oidc',
                               'oidc_client_id',
                               fallback='pretix')
        base_authorize_url = config.get(
            'pretix_oidc',
            'oidc_authorize_url',
            fallback='https://sso.example.com/auth')

        oauth2_session = OAuth2Session(client_id,
                                       scope='openid email profile',
                                       redirect_uri=redirect_uri)
        authorization_url, state = oauth2_session.authorization_url(
            base_authorize_url)

        # Store state in session for later validation (see auth.py)
        request.session['OAUTH2_STATE'] = state
        request.session['OAUTH2_REDIRECT_URI'] = redirect_uri

        return authorization_url
Ejemplo n.º 9
0
def refresh_mollie_tokens(sender, **kwargs):
    seen = set()
    gs = GlobalSettingsObject()
    for es in Event_SettingsStore.objects.filter(key='payment_mollie_expires'):
        if time.time() - float(es.object.settings.payment_mollie_expires) < 600:
            rt = es.object.settings.payment_mollie_refresh_token
            if rt not in seen:
                try:
                    resp = requests.post('https://api.mollie.com/oauth2/tokens', auth=(
                        gs.settings.payment_mollie_connect_client_id,
                        gs.settings.payment_mollie_connect_client_secret
                    ), data={
                        'grant_type': 'refresh_token',
                        'refresh_token': es.object.settings.payment_mollie_refresh_token,
                        'redirect_uri': build_absolute_uri('plugins:pretix_mollie:oauth.return')
                    })
                except:
                    logger.exception('Unable to refresh mollie token')
                    if float(es.object.settings.payment_mollie_expires) > time.time() and not \
                            es.object.settings.payment_mollie_api_key:
                        es.object.settings.payment_mollie__enabled = False
                        es.object.log_action('pretix_mollie.event.disabled')
                else:
                    if resp.status_code == 200:
                        data = resp.json()
                        for ev in Event_SettingsStore.objects.filter(key='payment_mollie_refresh_token', value=rt):
                            ev.object.settings.payment_mollie_access_token = data['access_token']
                            ev.object.settings.payment_mollie_refresh_token = data['refresh_token']
                            ev.object.settings.payment_mollie_expires = time.time() + data['expires_in']
                        seen.add(rt)
Ejemplo n.º 10
0
 def post(self, request, *args, **kwargs):
     if self.form.is_valid():
         user = self.form.cleaned_data['user']
         if user.email:
             mail(
                 user, _('Password recovery'),
                 'pretixpresale/email/forgot.txt',
                 {
                     'user': user,
                     'event': self.request.event,
                     'url': build_absolute_uri('presale:event.forgot.recover', kwargs={
                         'event': self.request.event.slug,
                         'organizer': self.request.event.organizer.slug,
                     }) + '?token=' + self.generate_token(user),
                 },
                 self.request.event
             )
             messages.success(request, _('We sent you an e-mail containing further instructions.'))
         else:
             messages.success(request, _('We are unable to send you a new password, as you did not enter an e-mail '
                                         'address at your registration.'))
         return redirect('presale:event.forgot',
                         organizer=self.request.event.organizer.slug,
                         event=self.request.event.slug)
     else:
         return self.get(request, *args, **kwargs)
Ejemplo n.º 11
0
 def post(self, request, *args, **kwargs):
     if self.form.is_valid():
         user = self.form.cleaned_data["user"]
         mail(
             user.email,
             _("Password recovery"),
             "pretixpresale/email/forgot.txt",
             {
                 "user": user,
                 "event": self.request.event,
                 "url": build_absolute_uri(
                     "presale:event.forgot.recover",
                     kwargs={"event": self.request.event.slug, "organizer": self.request.event.organizer.slug},
                 )
                 + "?id=%d&token=%s" % (user.id, default_token_generator.make_token(user)),
             },
             self.request.event,
             locale=user.locale,
         )
         messages.success(request, _("We sent you an e-mail containing further instructions."))
         return redirect(
             "presale:event.forgot", organizer=self.request.event.organizer.slug, event=self.request.event.slug
         )
     else:
         return self.get(request, *args, **kwargs)
Ejemplo n.º 12
0
def test_site_url_subpath():
    settings.SITE_URL = 'https://example.com/presale'
    old_prefix = urls.get_script_prefix()
    urls.set_script_prefix('/presale/')
    assert build_absolute_uri(
        'control:auth.login') == 'https://example.com/presale/control/login'
    urls.set_script_prefix(old_prefix)
Ejemplo n.º 13
0
    def post(self, request, *args, **kwargs):
        if self.form.is_valid():
            user = self.form.cleaned_data['user']

            if settings.HAS_REDIS:
                from django_redis import get_redis_connection
                rc = get_redis_connection("redis")
                if rc.exists('pretix_pwreset_%s' % (user.id)):
                    user.log_action('pretix.control.auth.user.forgot_password.denied.repeated')
                    messages.error(request, _('We already sent you an email in the last 24 hours.'))
                    return redirect('control:auth.forgot')
                else:
                    rc.setex('pretix_pwreset_%s' % (user.id), 3600 * 24, '1')

            mail(
                user.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
                {
                    'user': user,
                    'url': (build_absolute_uri('control:auth.forgot.recover')
                            + '?id=%d&token=%s' % (user.id, default_token_generator.make_token(user)))
                },
                None, locale=user.locale
            )
            user.log_action('pretix.control.auth.user.forgot_password.mail_sent')
            messages.success(request, _('We sent you an e-mail containing further instructions.'))
            return redirect('control:auth.forgot')
        else:
            return self.get(request, *args, **kwargs)
Ejemplo n.º 14
0
def perform_order(event: Event, payment_provider: BasePaymentProvider, positions: list, user: User=None,
                  email: str=None, locale: str=None):
    dt = now()

    try:
        with event.lock():
            check_positions(event, dt, positions)
            order = place_order(event, user, email if user is None else None, positions, dt, payment_provider,
                                locale=locale)
            mail(
                order.email, _('Your order: %(code)s') % {'code': order.code},
                'pretixpresale/email/order_placed.txt',
                {
                    'order': order,
                    'event': event,
                    'url': build_absolute_uri('presale:event.order', kwargs={
                        'event': event.slug,
                        'organizer': event.organizer.slug,
                        'order': order.code,
                    }) + '?order_secret=' + order.secret,
                    'payment': payment_provider.order_pending_mail_render(order)
                },
                event, locale=order.locale
            )
            return order
    except EventLock.LockTimeoutException:
        # Is raised when there are too many threads asking for event locks and we were
        # unable to get one
        raise OrderError(error_messages['busy'])
Ejemplo n.º 15
0
    def build_notification(self, logentry: LogEntry):
        order = logentry.content_object

        order_url = build_absolute_uri(
            'control:event.order',
            kwargs={
                'organizer': logentry.event.organizer.slug,
                'event': logentry.event.slug,
                'code': order.code
            }
        )

        n = Notification(
            event=logentry.event,
            title=self._title.format(order=order, event=logentry.event),
            url=order_url
        )
        n.add_attribute(_('Event'), order.event.name)
        n.add_attribute(_('Order code'), order.code)
        n.add_attribute(_('Order total'), money_filter(order.total, logentry.event.currency))
        n.add_attribute(_('Pending amount'), money_filter(order.pending_sum, logentry.event.currency))
        n.add_attribute(_('Order date'), date_format(order.datetime, 'SHORT_DATETIME_FORMAT'))
        n.add_attribute(_('Order status'), order.get_status_display())
        n.add_attribute(_('Order positions'), str(order.positions.count()))
        n.add_action(_('View order details'), order_url)
        return n
Ejemplo n.º 16
0
    def build_notification(self, logentry: LogEntry):
        order = logentry.content_object

        order_url = build_absolute_uri(
            'control:event.order',
            kwargs={
                'organizer': logentry.event.organizer.slug,
                'event': logentry.event.slug,
                'code': order.code
            }
        )

        n = Notification(
            event=logentry.event,
            title=self._title.format(order=order, event=logentry.event),
            url=order_url
        )
        n.add_attribute(_('Event'), order.event.name)
        n.add_attribute(_('Order code'), order.code)
        n.add_attribute(_('Order total'), money_filter(order.total, logentry.event.currency))
        n.add_attribute(_('Order date'), date_format(order.datetime, 'SHORT_DATETIME_FORMAT'))
        n.add_attribute(_('Order status'), order.get_status_display())
        n.add_attribute(_('Order positions'), str(order.positions.count()))
        n.add_action(_('View order details'), order_url)
        return n
Ejemplo n.º 17
0
def perform_order(event, user, payment_provider, positions):
    error_messages = {
        'busy': _('We were not able to process your request completely as the '
                  'server was too busy. Please try again.'),
    }
    dt = now()
    quotas_locked = set()

    try:
        check_positions(event, dt, positions, quotas_locked)
        order = place_order(event, user, positions, dt, payment_provider)
        mail(
            user, _('Your order: %(code)s') % {'code': order.code},
            'pretixpresale/email/order_placed.txt',
            {
                'user': user, 'order': order,
                'event': event,
                'url': build_absolute_uri('presale:event.order', kwargs={
                    'event': event.slug,
                    'organizer': event.organizer.slug,
                    'order': order.code,
                }),
                'payment': payment_provider.order_pending_mail_render(order)
            },
            event
        )
        return order
    except Quota.LockTimeoutException:
        # Is raised when there are too many threads asking for quota locks and we were
        # unaible to get one
        raise OrderError(error_messages['busy'])
    finally:
        # Release the locks. This is important ;)
        for quota in quotas_locked:
            quota.release()
Ejemplo n.º 18
0
 def generate_order_url(self, code, secret):
     return build_absolute_uri('presale:event.order',
                               kwargs={
                                   'event': self.request.event.slug,
                                   'organizer':
                                   self.request.event.organizer.slug,
                                   'order': code,
                                   'secret': secret
                               })
Ejemplo n.º 19
0
    def build_notification(self, logentry: LogEntry):
        order = logentry.content_object

        order_url = build_absolute_uri(
            'control:event.order',
            kwargs={
                'organizer': logentry.event.organizer.slug,
                'event': logentry.event.slug,
                'code': order.code
            }
        )

        n = Notification(
            event=logentry.event,
            title=self._title.format(order=order, event=logentry.event),
            url=order_url
        )
        n.add_attribute(_('Event'), order.event.name)
        if order.event.has_subevents:
            ses = []
            for se in self.event.subevents.filter(id__in=order.positions.values_list('subevent', flat=True)):
                ses.append('{} ({})'.format(se.name, se.get_date_range_display()))
            n.add_attribute(pgettext_lazy('subevent', 'Dates'), '\n'.join(ses))
        else:
            n.add_attribute(_('Event date'), order.event.get_date_range_display())

        positions = list(order.positions.select_related('item', 'variation', 'subevent'))
        fees = list(order.fees.all())

        n.add_attribute(_('Order code'), order.code)
        n.add_attribute(_('Net total'), money_filter(sum([p.net_price for p in positions] + [f.net_value for f in fees]), logentry.event.currency))
        n.add_attribute(_('Order total'), money_filter(order.total, logentry.event.currency))
        n.add_attribute(_('Pending amount'), money_filter(order.pending_sum, logentry.event.currency))
        n.add_attribute(_('Order date'), date_format(order.datetime.astimezone(logentry.event.timezone), 'SHORT_DATETIME_FORMAT'))
        n.add_attribute(_('Order status'), order.get_status_display())
        n.add_attribute(_('Order positions'), str(order.positions.count()))

        def sortkey(op):
            return op.item_id, op.variation_id, op.subevent_id

        def groupkey(op):
            return op.item, op.variation, op.subevent

        cart = [(k, list(v)) for k, v in groupby(sorted(positions, key=sortkey), key=groupkey)]
        items = []
        for (item, variation, subevent), pos in cart:
            ele = [str(len(pos)) + 'x ' + str(item)]
            if variation:
                ele.append(str(variation.value))
            if subevent:
                ele.append(str(subevent))
            items.append(' – '.join(ele))
        n.add_attribute(_('Purchased products'), '\n'.join(items))
        n.add_action(_('View order details'), order_url)
        return n
Ejemplo n.º 20
0
 def checkout_prepare(self, request, cart):
     self.init_api()
     items = []
     for cp in cart['positions']:
         items.append({
             "name": cp.item.name,
             "description": str(cp.variation) if cp.variation else "",
             "quantity": cp.count,
             "price": str(cp.price),
             "currency": request.event.currency
         })
     if cart['payment_fee']:
         items.append({
             "name": __('Payment method fee'),
             "description": "",
             "quantity": 1,
             "currency": request.event.currency,
             "price": str(cart['payment_fee'])
         })
     payment = paypalrestsdk.Payment({
         'intent': 'sale',
         'payer': {
             "payment_method": "paypal",
         },
         "redirect_urls": {
             "return_url": build_absolute_uri('plugins:paypal:return'),
             "cancel_url": build_absolute_uri('plugins:paypal:abort'),
         },
         "transactions": [
             {
                 "item_list": {
                     "items": items
                 },
                 "amount": {
                     "currency": request.event.currency,
                     "total": str(cart['total'])
                 },
                 "description": __('Event tickets for %s') % request.event.name
             }
         ]
     })
     return self._create_payment(request, payment)
Ejemplo n.º 21
0
    def send_password_reset(self):
        from pretix.base.services.mail import mail

        mail(
            self.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
            {
                'user': self,
                'url': (build_absolute_uri('control:auth.forgot.recover')
                        + '?id=%d&token=%s' % (self.id, default_token_generator.make_token(self)))
            },
            None, locale=self.locale
        )
Ejemplo n.º 22
0
Archivo: mail.py Proyecto: akuks/pretix
def mail(email: str, subject: str, template: str, context: dict=None, event: Event=None, locale: str=None):
    """
    Sends out an email to a user.

    :param user: The user this should be sent to.
    :param subject: The e-mail subject. Should be localized.
    :param template: The filename of a template to be used. It will
                     be rendered with the recipient's locale. Alternatively, you
                     can pass a LazyI18nString and leave ``context`` empty
    :param context: The context for rendering the template.
    :param event: The event, used for determining the sender of the e-mail

    :return: ``False`` on obvious failures, like the user having to e-mail
    address, ``True`` otherwise. ``True`` does not necessarily mean that
    the email has been sent, just that it has been queued by the e-mail
    backend.
    """
    _lng = translation.get_language()
    translation.activate(locale or settings.LANGUAGE_CODE)

    if isinstance(template, LazyI18nString):
        body = str(template)
    else:
        tpl = get_template(template)
        body = tpl.render(context)

    sender = event.settings.get('mail_from') if event else settings.MAIL_FROM

    subject = str(subject)
    prefix = event.settings.get('mail_prefix')
    if prefix:
        subject = "[%s] %s" % (prefix, subject)

    body += "\r\n\r\n----\r\n"
    body += _(
        "You are receiving this e-mail because you placed an order for %s." % event.name
    )
    body += "\r\n"
    body += _(
        "You can view all of your orders at the following URL:"
    )
    body += "\r\n"
    body += build_absolute_uri(
        'presale:event.orders', kwargs={
            'event': event.slug,
            'organizer': event.organizer.slug
        }
    )
    body += "\r\n"
    try:
        return mail_send([email], subject, body, sender)
    finally:
        translation.activate(_lng)
Ejemplo n.º 23
0
def mark_order_paid(order, provider=None, info=None, date=None, manual=None, force=False):
    """
    Marks an order as paid. This clones the order object, sets the payment provider,
    info and date and returns the cloned order object.

    :param provider: The payment provider that marked this as paid
    :type provider: str
    :param info: The information to store in order.payment_info
    :type info: str
    :param date: The date the payment was received (if you pass ``None``, the current
                 time will be used).
    :type date: datetime
    :param force: Whether this payment should be marked as paid even if no remaining
                  quota is available (default: ``False``).
    :type force: boolean
    :raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False``
    """
    can_be_paid, quotas_locked = order._can_be_paid(keep_locked=True)
    if not force and can_be_paid is not True:
        raise Quota.QuotaExceededException(can_be_paid)
    order = order.clone()
    order.payment_provider = provider or order.payment_provider
    order.payment_info = info or order.payment_info
    order.payment_date = date or now()
    if manual is not None:
        order.payment_manual = manual
    order.status = Order.STATUS_PAID
    order.save()
    order_paid.send(order.event, order=order)

    if quotas_locked:
        for quota in quotas_locked:
            quota.release()

    from pretix.base.services.mail import mail

    mail(
        order.user, _('Payment received for your order: %(code)s') % {'code': order.code},
        'pretixpresale/email/order_paid.txt',
        {
            'user': order.user,
            'order': order,
            'event': order.event,
            'url': build_absolute_uri('presale:event.order', kwargs={
                'event': order.event.slug,
                'organizer': order.event.organizer.slug,
                'order': order.code,
            }),
            'downloads': order.event.settings.get('ticket_download', as_type=bool)
        },
        order.event
    )
    return order
Ejemplo n.º 24
0
    def send_password_reset(self):
        from pretix.base.services.mail import mail

        mail(
            self.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
            {
                'user': self,
                'url': (build_absolute_uri('control:auth.forgot.recover')
                        + '?id=%d&token=%s' % (self.id, default_token_generator.make_token(self)))
            },
            None, locale=self.locale
        )
Ejemplo n.º 25
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })
        if self.object.subevent:
            url = build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug,
                'subevent': self.object.subevent.pk
            })

        data = {
            'version': API_VERSION,
            'url': url[:-7],  # the slice removes the redeem/ part at the end
            'key': self.object.key,
            'allow_search': self.object.allow_search,
            'show_info': self.object.show_info
        }
        ctx['config'] = self.object
        ctx['query'] = urllib.parse.urlencode(data, safe=':/')
        ctx['qrdata'] = json.dumps(data)
        return ctx
Ejemplo n.º 26
0
 def post(self, request, *args, **kwargs):
     if self.form.is_valid():
         user = self.form.cleaned_data['user']
         mail(
             user.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
             {
                 'user': user,
                 'url': (build_absolute_uri('control:auth.forgot.recover')
                         + '?id=%d&token=%s' % (user.id, default_token_generator.make_token(user)))
             },
             None, locale=user.locale
         )
         messages.success(request, _('We sent you an e-mail containing further instructions.'))
         return redirect('control:auth.forgot')
     else:
         return self.get(request, *args, **kwargs)
Ejemplo n.º 27
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(
            gettext_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.º 28
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        key = self.request.event.settings.get('pretixdroid_key')
        if not key or 'flush_key' in self.request.GET:
            key = get_random_string(length=32,
                                    allowed_chars=string.ascii_uppercase + string.ascii_lowercase + string.digits)
            self.request.event.settings.set('pretixdroid_key', key)

        ctx['qrdata'] = json.dumps({
            'version': API_VERSION,
            'url': build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug
            })[:-7],  # the slice removes the redeem/ part at the end
            'key': key
        })
        return ctx
Ejemplo n.º 29
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        key = self.request.event.settings.get('pretixdroid_key')
        if not key or 'flush_key' in self.request.GET:
            key = get_random_string(length=32,
                                    allowed_chars=string.ascii_uppercase + string.ascii_lowercase + string.digits)
            self.request.event.settings.set('pretixdroid_key', key)

        ctx['qrdata'] = json.dumps({
            'version': API_VERSION,
            'url': build_absolute_uri('plugins:pretixdroid:api.redeem', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug
            })[:-7],  # the slice removes the redeem/ part at the end
            'key': key
        })
        return ctx
Ejemplo n.º 30
0
def refresh_mollie_token(event, disable=True):
    # Rate limit
    rt = event.settings.payment_mollie_refresh_token
    if not rt:
        return False
    h = hashlib.sha1(rt.encode()).hexdigest()
    if cache.get('mollie_refresh_{}'.format(h)):
        return False
    cache.set('mollie_refresh_{}'.format(h), 'started', 30)

    gs = GlobalSettingsObject()
    try:
        resp = requests.post(
            'https://api.mollie.com/oauth2/tokens',
            auth=(gs.settings.payment_mollie_connect_client_id,
                  gs.settings.payment_mollie_connect_client_secret),
            data={
                'grant_type':
                'refresh_token',
                'refresh_token':
                event.settings.payment_mollie_refresh_token,
                'redirect_uri':
                build_absolute_uri('plugins:pretix_mollie:oauth.return')
            })
    except Exception as e:
        logger.exception('Unable to refresh mollie token')
        if float(event.settings.payment_mollie_expires) > time.time() and not \
                event.settings.payment_mollie_api_key and disable:
            event.settings.payment_mollie__enabled = False
            event.log_action('pretix_mollie.event.disabled',
                             {'reason': str(e)})
        return False
    else:
        if resp.status_code == 200:
            data = resp.json()
            for ev in Event_SettingsStore.objects.filter(
                    key='payment_mollie_refresh_token', value=rt):
                ev.object.settings.payment_mollie_access_token = data[
                    'access_token']
                ev.object.settings.payment_mollie_refresh_token = data[
                    'refresh_token']
                ev.object.settings.payment_mollie_expires = time.time(
                ) + data['expires_in']
            return True
    return False
Ejemplo n.º 31
0
    def send_security_notice(self, messages, email=None):
        from pretix.base.services.mail import mail, SendMailException

        try:
            with language(self.locale):
                msg = '- ' + '\n- '.join(str(m) for m in messages)

            mail(email or self.email,
                 _('Account information changed'),
                 'pretixcontrol/email/security_notice.txt', {
                     'user': self,
                     'messages': msg,
                     'url': build_absolute_uri('control:user.settings')
                 },
                 event=None,
                 locale=self.locale)
        except SendMailException:
            pass  # Already logged
Ejemplo n.º 32
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        key = self.request.event.settings.get('pretixdroid_key')
        if not key or 'flush_key' in self.request.GET:
            key = ''.join(
                random.SystemRandom().choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in
                range(32))
            self.request.event.settings.set('pretixdroid_key', key)

        ctx['qrdata'] = json.dumps({
            'version': 1,
            'url': build_absolute_uri('plugins:pretixdroid:api', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug
            }),
            'key': key
        })
        return ctx
Ejemplo n.º 33
0
 def _send_invite(self, instance):
     try:
         mail(
             instance.invite_email,
             _('Account information changed'),
             'pretixcontrol/email/invitation_organizer.txt', {
                 'user':
                 self,
                 'organizer':
                 self.request.organizer.name,
                 'url':
                 build_absolute_uri('control:auth.invite',
                                    kwargs={'token': instance.invite_token})
             },
             event=None,
             locale=self.request.LANGUAGE_CODE)
     except SendMailException:
         pass  # Already logged
Ejemplo n.º 34
0
    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        key = self.request.event.settings.get('pretixdroid_key')
        if not key or 'flush_key' in self.request.GET:
            key = ''.join(
                random.SystemRandom().choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in
                range(32))
            self.request.event.settings.set('pretixdroid_key', key)

        ctx['qrdata'] = json.dumps({
            'version': 1,
            'url': build_absolute_uri('plugins:pretixdroid:api', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug
            }),
            'key': key
        })
        return ctx
Ejemplo n.º 35
0
    def build_notification(self, logentry: LogEntry):
        control_url = build_absolute_uri(
            'control:event.requiredactions',
            kwargs={
                'organizer': logentry.event.organizer.slug,
                'event': logentry.event.slug,
            }
        )

        n = Notification(
            event=logentry.event,
            title=_('Administrative action required'),
            detail=_('Something happened in your event that our system cannot handle automatically, e.g. an external '
                     'refund. You need to resolve it manually or choose to ignore it, depending on the issue at hand.'),
            url=control_url
        )
        n.add_action(_('View all unresolved problems'), control_url)
        return n
Ejemplo n.º 36
0
    def build_notification(self, logentry: LogEntry):
        control_url = build_absolute_uri(
            'control:event.requiredactions',
            kwargs={
                'organizer': logentry.event.organizer.slug,
                'event': logentry.event.slug,
            }
        )

        n = Notification(
            event=logentry.event,
            title=_('Administrative action required'),
            detail=_('Something happened in your event that our system cannot handle automatically, e.g. an external '
                     'refund. You need to resolve it manually or choose to ignore it, depending on the issue at hand.'),
            url=control_url
        )
        n.add_action(_('View all unresolved problems'), control_url)
        return n
Ejemplo n.º 37
0
 def _send_invite(self, instance):
     try:
         mail(
             instance.email,
             _('pretix account invitation'),
             'pretixcontrol/email/invitation.txt',
             {
                 'user': self,
                 'organizer': self.request.organizer.name,
                 'team': instance.team.name,
                 'url': build_absolute_uri('control:auth.invite', kwargs={
                     'token': instance.token
                 })
             },
             event=None,
             locale=self.request.LANGUAGE_CODE
         )
     except SendMailException:
         pass  # Already logged
Ejemplo n.º 38
0
 def _send_invite(self, instance):
     try:
         mail(
             instance.email,
             _('pretix account invitation'),
             'pretixcontrol/email/invitation.txt',
             {
                 'user': self,
                 'organizer': self.context['organizer'].name,
                 'team': instance.team.name,
                 'url': build_absolute_uri('control:auth.invite', kwargs={
                     'token': instance.token
                 })
             },
             event=None,
             locale=get_language_without_region()  # TODO: expose?
         )
     except SendMailException:
         pass  # Already logged
Ejemplo n.º 39
0
    def build_notification(self, logentry: LogEntry):
        order = logentry.content_object

        order_url = build_absolute_uri('control:event.order',
                                       kwargs={
                                           'organizer':
                                           logentry.event.organizer.slug,
                                           'event': logentry.event.slug,
                                           'code': order.code
                                       })

        n = Notification(event=logentry.event,
                         title=self._title.format(order=order,
                                                  event=logentry.event),
                         url=order_url)
        n.add_attribute(_('Event'), order.event.name)
        if order.event.has_subevents:
            ses = []
            for se in self.event.subevents.filter(
                    id__in=order.positions.values_list('subevent', flat=True)):
                ses.append('{} ({})'.format(se.name,
                                            se.get_date_range_display()))
            n.add_attribute(pgettext_lazy('subevent', 'Dates'), '\n'.join(ses))
        else:
            n.add_attribute(_('Event date'),
                            order.event.get_date_range_display())
        n.add_attribute(_('Order code'), order.code)
        n.add_attribute(_('Order total'),
                        money_filter(order.total, logentry.event.currency))
        n.add_attribute(
            _('Pending amount'),
            money_filter(order.pending_sum, logentry.event.currency))
        n.add_attribute(_('Order date'),
                        date_format(order.datetime, 'SHORT_DATETIME_FORMAT'))
        n.add_attribute(_('Order status'), order.get_status_display())
        n.add_attribute(_('Order positions'), str(order.positions.count()))
        items = []
        for it in self.event.items.filter(
                id__in=order.positions.values_list('item', flat=True)):
            items.append(str(it.name))
        n.add_attribute(_('Purchased products'), '\n'.join(items))
        n.add_action(_('View order details'), order_url)
        return n
Ejemplo n.º 40
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.º 41
0
 def post(self, request, *args, **kwargs):
     if self.form.is_valid():
         user = self.form.cleaned_data['user']
         mail(user.email,
              _('Password recovery'),
              'pretixcontrol/email/forgot.txt', {
                  'user':
                  user,
                  'url':
                  (build_absolute_uri('control:auth.forgot.recover') +
                   '?id=%d&token=%s' %
                   (user.id, default_token_generator.make_token(user)))
              },
              None,
              locale=user.locale)
         messages.success(
             request,
             _('We sent you an e-mail containing further instructions.'))
         return redirect('control:auth.forgot')
     else:
         return self.get(request, *args, **kwargs)
Ejemplo n.º 42
0
    def send_security_notice(self, messages, email=None):
        from pretix.base.services.mail import mail, SendMailException

        try:
            with language(self.locale):
                msg = '- ' + '\n- '.join(str(m) for m in messages)

            mail(
                email or self.email,
                _('Account information changed'),
                'pretixcontrol/email/security_notice.txt',
                {
                    'user': self,
                    'messages': msg,
                    'url': build_absolute_uri('control:user.settings')
                },
                event=None,
                locale=self.locale
            )
        except SendMailException:
            pass  # Already logged
Ejemplo n.º 43
0
def _perform_order(event: Event, payment_provider: BasePaymentProvider, position_ids: list,
                   email: str, locale: str):
    event = Event.objects.current.get(identity=event)
    responses = register_payment_providers.send(event)
    pprov = None
    for receiver, response in responses:
        provider = response(event)
        if provider.identifier == payment_provider:
            pprov = provider
    if not pprov:
        raise OrderError(error_messages['internal'])

    dt = now()
    with event.lock():
        positions = list(CartPosition.objects.current.filter(
            identity__in=position_ids).select_related('item', 'variation'))
        if len(position_ids) != len(positions):
            raise OrderError(error_messages['internal'])
        _check_positions(event, dt, positions)
        order = _create_order(event, email, positions, dt, pprov,
                              locale=locale)
        mail(
            order.email, _('Your order: %(code)s') % {'code': order.code},
            'pretixpresale/email/order_placed.txt',
            {
                'order': order,
                'event': event,
                'url': build_absolute_uri('presale:event.order', kwargs={
                    'event': event.slug,
                    'organizer': event.organizer.slug,
                    'order': order.code,
                    'secret': order.secret
                }),
                'payment': pprov.order_pending_mail_render(order)
            },
            event, locale=order.locale
        )
        return order.identity
Ejemplo n.º 44
0
def test_site_url_domain():
    settings.SITE_URL = 'https://example.com'
    assert build_absolute_uri(
        'control:auth.login') == 'https://example.com/control/login'
Ejemplo n.º 45
0
 def settings_content_render(self, request):
     return "<div class='alert alert-info'>%s<br /><code>%s</code></div>" % (
         _('Please configure a <a href="https://dashboard.stripe.com/account/webhooks">Stripe Webhook</a> to '
           'the following endpoint in order to automatically cancel orders when a charges are refunded externally.'
           ), build_absolute_uri('plugins:stripe:webhook'))
Ejemplo n.º 46
0
 def settings_content_render(self, request):
     return "<div class='alert alert-info'>%s<br /><code>%s</code></div>" % (
         _('Please configure a <a href="https://dashboard.stripe.com/account/webhooks">Stripe Webhook</a> to '
           'the following endpoint in order to automatically cancel orders when a charges are refunded externally.'),
         build_absolute_uri('plugins:stripe:webhook')
     )
Ejemplo n.º 47
0
def test_site_url_subpath():
    settings.SITE_URL = 'https://example.com/presale'
    old_prefix = urlresolvers.get_script_prefix()
    urlresolvers.set_script_prefix('/presale/')
    assert build_absolute_uri('control:auth.login') == 'https://example.com/presale/control/login'
    urlresolvers.set_script_prefix(old_prefix)
Ejemplo n.º 48
0
def oauth_return(request, *args, **kwargs):
    if 'payment_mollie_oauth_event' not in request.session:
        messages.error(request, _('An error occurred during connecting with Mollie, please try again.'))
        return redirect(reverse('control:index'))

    event = get_object_or_404(Event, pk=request.session['payment_mollie_oauth_event'])

    if request.GET.get('state') != request.session['payment_mollie_oauth_token']:
        messages.error(request, _('An error occurred during connecting with Mollie, please try again.'))
        return redirect(reverse('control:event.settings.payment.provider', kwargs={
            'organizer': event.organizer.slug,
            'event': event.slug,
            'provider': 'mollie'
        }))

    gs = GlobalSettingsObject()

    try:
        resp = requests.post('https://api.mollie.com/oauth2/tokens', auth=(
            gs.settings.payment_mollie_connect_client_id,
            gs.settings.payment_mollie_connect_client_secret
        ), data={
            'grant_type': 'authorization_code',
            'code': request.GET.get('code'),
            'redirect_uri': build_absolute_uri('plugins:pretix_mollie:oauth.return'),
        })
        resp.raise_for_status()
        data = resp.json()

        if 'error' not in data:
            orgaresp = requests.get('https://api.mollie.com/v2/organizations/me', headers={
                'Authorization': 'Bearer ' + data.get('access_token')
            })
            orgaresp.raise_for_status()
            orgadata = orgaresp.json()

            profilesurl = 'https://api.mollie.com/v2/profiles'
            profiles = []
            while profilesurl:
                profilesresp = requests.get(profilesurl, headers={
                    'Authorization': 'Bearer ' + data.get('access_token')
                })
                profilesresp.raise_for_status()
                d = profilesresp.json()
                profiles += d['_embedded']['profiles']
                if d['_links']['next']:
                    profilesurl = d['_links']['next']['href']
                else:
                    profilesurl = None
    except:
        logger.exception('Failed to obtain OAuth token')
        messages.error(request, _('An error occurred during connecting with Mollie, please try again.'))
    else:
        if 'error' in data:
            messages.error(request, _('Mollie returned an error: {}').format(data['error_description']))
        elif not profiles:
            messages.error(request, _('Please create a website profile in your Mollie account and try again.'))
        elif not orgadata.get('id', '') or not orgadata.get('name', ''):
            messages.error(request, _('Please fill in your company details in your Mollie account and try again.'))
        else:
            messages.success(request,
                             _('Your Mollie account is now connected to pretix. You can change the settings in '
                               'detail below.'))
            event.settings.payment_mollie_access_token = data['access_token']
            event.settings.payment_mollie_refresh_token = data['refresh_token']
            event.settings.payment_mollie_expires = time.time() + data['expires_in']
            event.settings.payment_mollie_connect_org_id = orgadata.get('id')
            event.settings.payment_mollie_connect_org_name = orgadata.get('name', '')
            event.settings.payment_mollie_connect_profiles = [
                [
                    p.get('id'),
                    p.get('name') + ' - ' + p.get('website', '')
                ] for p in profiles
            ]
            event.settings.payment_mollie_connect_profile = profiles[0].get('id')

            if request.session.get('payment_mollie_oauth_enable', False):
                event.settings.payment_mollie__enabled = True
                del request.session['payment_mollie_oauth_enable']

    return redirect(reverse('control:event.settings.payment.provider', kwargs={
        'organizer': event.organizer.slug,
        'event': event.slug,
        'provider': 'mollie'
    }))
Ejemplo n.º 49
0
def test_site_url_domain():
    settings.SITE_URL = 'https://example.com'
    assert build_absolute_uri('control:auth.login') == 'https://example.com/control/login'