def form_valid(self, form): if form.cleaned_data['email'] != self.initial_email: new_email = form.cleaned_data['email'] form.cleaned_data['email'] = form.instance.email = self.initial_email ctx = form.instance.get_email_context() ctx['url'] = build_absolute_uri( self.request.organizer, 'presale:organizer.customer.change.confirm' ) + '?token=' + dumps({ 'customer': form.instance.pk, 'email': new_email }, salt='pretix.presale.views.customer.ChangeInformationView') mail( new_email, _('Confirm email address for your account at {organizer}').format(organizer=self.request.organizer.name), self.request.organizer.settings.mail_text_customer_email_change, ctx, locale=form.instance.locale, customer=form.instance, organizer=self.request.organizer, ) messages.success(self.request, _('Your changes have been saved. We\'ve sent you an email with a link to update your ' 'email address. The email address of your account will be changed as soon as you ' 'click that link.')) else: messages.success(self.request, _('Your changes have been saved.')) with transaction.atomic(): form.save() d = dict(form.cleaned_data) del d['email'] self.request.customer.log_action('pretix.customer.changed', d) update_customer_session_auth_hash(self.request, form.instance) return HttpResponseRedirect(self.get_success_url())
def form_valid(self, form): qs = Order.objects.filter(event=self.request.event) statusq = Q(status__in=form.cleaned_data['sendto']) if 'overdue' in form.cleaned_data['sendto']: statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now()) orders = qs.filter(statusq) self.request.event.log_action('pretix.plugins.sendmail.sent', user=self.request.user, data=dict( form.cleaned_data)) failures = [] for o in orders: try: mail(o.email, form.cleaned_data['subject'], form.cleaned_data['message'], None, self.request.event, locale=o.locale, order=o) except SendMailException: failures.append(o.email) if failures: messages.error(self.request, _('Failed to send mails to the following users: {}'.format(' '.join(failures)))) else: messages.success(self.request, _('Your message has been queued to be sent to the selected users.')) return redirect( 'plugins:sendmail:send', event=self.request.event.slug, organizer=self.request.event.organizer.slug )
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'])
def _perform_order(event: str, payment_provider: str, position_ids: List[str], email: str, locale: str, address: int, meta_info: dict=None): event = Event.objects.get(id=event) responses = register_payment_providers.send(event) pprov = None for rec, response in responses: provider = response(event) if provider.identifier == payment_provider: pprov = provider if not pprov: raise OrderError(error_messages['internal']) with event.lock() as now_dt: positions = list(CartPosition.objects.filter( id__in=position_ids).select_related('item', 'variation')) if len(positions) == 0: raise OrderError(error_messages['empty']) if len(position_ids) != len(positions): raise OrderError(error_messages['internal']) _check_positions(event, now_dt, positions) order = _create_order(event, email, positions, now_dt, pprov, locale=locale, address=address, meta_info=meta_info) if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order): if not order.invoices.exists(): generate_invoice(order) if order.total == Decimal('0.00'): mailtext = event.settings.mail_text_order_free else: mailtext = event.settings.mail_text_order_placed try: invoice_name = order.invoice_address.name invoice_company = order.invoice_address.company except InvoiceAddress.DoesNotExist: invoice_name = "" invoice_company = "" mail( order.email, _('Your order: %(code)s') % {'code': order.code}, mailtext, { 'total': LazyNumber(order.total), 'currency': event.currency, 'date': LazyDate(order.expires), 'event': event.name, 'url': build_absolute_uri(event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'paymentinfo': str(pprov.order_pending_mail_render(order)), 'invoice_name': invoice_name, 'invoice_company': invoice_company, }, event, locale=order.locale ) return order.id
def send_mail(self, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any] = None, log_entry_type: str = 'pretix.event.order.email.sent', user: User = None, headers: dict = None, sender: str = None, invoices: list = None): """ Sends an email to the user that placed this order. Basically, this method does two things: * Call ``pretix.base.services.mail.mail`` with useful values for the ``event``, ``locale``, ``recipient`` and ``order`` parameters. * Create a ``LogEntry`` with the email contents. :param subject: Subject of the email :param template: LazyI18nString or template filename, see ``pretix.base.services.mail.mail`` for more details :param context: Dictionary to use for rendering the template :param log_entry_type: Key to be used for the log entry :param user: Administrative user who triggered this mail to be sent :param headers: Dictionary with additional mail headers :param sender: Custom email sender. """ from pretix.base.services.mail import SendMailException, mail, render_mail if not self.email: return with language(self.locale): recipient = self.email try: email_content = render_mail(template, context)[0] mail(recipient, subject, template, context, self.event, self.locale, self, headers, sender, invoices=invoices) except SendMailException: raise else: self.log_action(log_entry_type, user=user, data={ 'subject': subject, 'message': email_content, 'recipient': recipient, 'invoices': [i.pk for i in invoices] if invoices else [] })
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)
def post(self, *args, **kwargs): with language(self.order.locale): try: mail(self.order.email, _('Your order: %(code)s') % {'code': self.order.code}, self.order.event.settings.mail_text_resend_link, { 'event': self.order.event.name, 'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={ 'order': self.order.code, 'secret': self.order.secret }), }, self.order.event, locale=self.order.locale) except SendMailException: messages.error( self.request, _('There was an error sending the mail. Please try again later.' )) return redirect(self.get_order_url()) messages.success(self.request, _('The email has been queued to be sent.')) self.order.log_action('pretix.event.order.resend', user=self.request.user) return redirect(self.get_order_url())
def _notify_user(self): with language(self.order.locale): try: invoice_name = self.order.invoice_address.name invoice_company = self.order.invoice_address.company except InvoiceAddress.DoesNotExist: invoice_name = "" invoice_company = "" mail(self.order.email, _('Your order has been changed: %(code)s') % {'code': self.order.code}, self.order.event.settings.mail_text_order_changed, { 'event': self.order.event.name, 'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={ 'order': self.order.code, 'secret': self.order.secret }), 'invoice_name': invoice_name, 'invoice_company': invoice_company, }, self.order.event, locale=self.order.locale)
def send_expiry_warnings(sender, **kwargs): eventcache = {} today = now().replace(hour=0, minute=0, second=0) for o in Order.objects.filter(expires__gte=today, expiry_reminder_sent=False, status=Order.STATUS_PENDING).select_related('event'): settings = eventcache.get(o.event.pk, None) if settings is None: settings = o.event.settings eventcache[o.event.pk] = settings days = settings.get('mail_days_order_expire_warning', as_type=int) if days and (o.expires - today).days <= days: o.expiry_reminder_sent = True o.save() try: mail( o.email, _('Your order is about to expire: %(code)s') % {'code': o.code}, settings.mail_text_order_expire_warning, { 'event': o.event.name, 'url': build_absolute_uri(o.event, 'presale:event.order', kwargs={ 'order': o.code, 'secret': o.secret }), 'expire_date': date_format(o.expires, 'SHORT_DATE_FORMAT') }, o.event, locale=o.locale ) except SendMailException: logger.exception('Reminder email could not be sent') else: o.log_action('pretix.event.order.expire_warning_sent')
def _send_confirmation_email(self, *args, **kwargs): locale = 'en' email = kwargs.pop('email') name = kwargs.pop('name') event = kwargs.pop('event') with language(locale): email_content = LazyI18nString.from_gettext( ugettext_noop("""Dear {name} , Thank you for applying for an IFF Ticket. We are currently reviewing ticket requests, and as space becomes available, we will be issuing tickets. If you have any questions, please email [email protected] Best regards, Your {event} team""")) email_context = {'event': event, 'name': name} mail(email, _('Your {event} ticket request').format(event=str(event)), email_content, email_context, event, locale=locale)
def _mail(self): # Mail the code to self.email # return the verification code # code will be stored in the session by the view locale = 'en' with language(locale): email_content = LazyI18nString.from_gettext( ugettext_noop("""Hello, Here's your verification code. Use it to validate your email and continue the checkout process. {code} Best regards, Your {event} team""")) email_context = {'event': self.event, 'code': self.code} mail(self.email, _("Here's your verification code for {event}").format( event=str(self.event)), email_content, email_context, self.event, locale=locale)
def post(self, request, *args, **kwargs): if not self.link_form.is_valid(): messages.error(self.request, _('We had difficulties processing your input.')) return self.get(request, *args, **kwargs) user = self.link_form.cleaned_data.get('email') if settings.HAS_REDIS: from django_redis import get_redis_connection rc = get_redis_connection("redis") if rc.exists('pretix_resend_{}'.format(user)): messages.error(request, _('We already sent you an email in the last 24 hours.')) return redirect(eventreverse(self.request.event, 'presale:event.resend_link')) else: rc.setex('pretix_resend_{}'.format(user), 3600 * 24, '1') orders = self.request.event.orders.filter(email__iexact=user) if not orders: user = INVALID_ADDRESS subject = _('Your orders for {}').format(self.request.event) template = self.request.event.settings.mail_text_resend_all_links context = get_email_context(event=self.request.event, orders=orders) try: mail(user, subject, template, context, event=self.request.event, locale=self.request.LANGUAGE_CODE) except SendMailException: logger = logging.getLogger('pretix.presale.user') logger.exception('A mail resending order links to {} could not be sent.'.format(user)) messages.error(self.request, _('We have trouble sending emails right now, please check back later.')) return self.get(request, *args, **kwargs) messages.success(self.request, _('If there were any orders by this user, they will receive an email with their order codes.')) return redirect(eventreverse(self.request.event, 'presale:event.index'))
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)
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)
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)
def create(self): customer = self.request.organizer.customers.create( email=self.cleaned_data['email'], name_parts=self.cleaned_data['name_parts'], is_active=True, is_verified=False, locale=get_language_without_region(), ) customer.set_unusable_password() customer.save() customer.log_action('pretix.customer.created', {}) ctx = customer.get_email_context() token = TokenGenerator().make_token(customer) ctx['url'] = build_absolute_uri( self.request.organizer, 'presale:organizer.customer.activate' ) + '?id=' + customer.identifier + '&token=' + token mail( customer.email, _('Activate your account at {organizer}').format( organizer=self.request.organizer.name), self.request.organizer.settings.mail_text_customer_registration, ctx, locale=customer.locale, customer=customer, organizer=self.request.organizer, ) return customer
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()
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)
def send_voucher(self, quota_cache=None, user=None, auth=None): availability = (self.variation.check_quotas(count_waitinglist=False, subevent=self.subevent, _cache=quota_cache) if self.variation else self.item.check_quotas( count_waitinglist=False, subevent=self.subevent, _cache=quota_cache)) if availability[1] is None or availability[1] < 1: raise WaitingListException( _('This product is currently not available.')) if self.voucher: raise WaitingListException( _('A voucher has already been sent to this person.')) if '@' not in self.email: raise WaitingListException( _('This entry is anonymized and can no longer be used.')) with transaction.atomic(): v = Voucher.objects.create( event=self.event, max_usages=1, valid_until=now() + timedelta(hours=self.event.settings.waiting_list_hours), item=self.item, variation=self.variation, tag='waiting-list', comment=_( 'Automatically created from waiting list entry for {email}' ).format(email=self.email), block_quota=True, subevent=self.subevent, ) v.log_action( 'pretix.voucher.added.waitinglist', { 'item': self.item.pk, 'variation': self.variation.pk if self.variation else None, 'tag': 'waiting-list', 'block_quota': True, 'valid_until': v.valid_until.isoformat(), 'max_usages': 1, 'email': self.email, 'waitinglistentry': self.pk, 'subevent': self.subevent.pk if self.subevent else None, }, user=user, auth=auth) self.log_action('pretix.waitinglist.voucher', user=user, auth=auth) self.voucher = v self.save() with language(self.locale): mail(self.email, _('You have been selected from the waitinglist for {event}'). format(event=str(self.event)), self.event.settings.mail_text_waiting_list, get_email_context(event=self.event, waiting_list_entry=self), self.event, locale=self.locale)
def form_valid(self, form): qs = Order.objects.filter(event=self.request.event) statusq = Q(status__in=form.cleaned_data['sendto']) if 'overdue' in form.cleaned_data['sendto']: statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now()) orders = qs.filter(statusq) self.request.event.log_action('pretix.plugins.sendmail.sent', user=self.request.user, data=dict( form.cleaned_data)) tz = pytz.timezone(self.request.event.settings.timezone) failures = [] self.output = {} for o in orders: if self.request.POST.get("action") == "preview": for l in self.request.event.settings.locales: with language(l): self.output[l] = [] self.output[l].append(_('Subject: {subject}').format(subject=form.cleaned_data['subject'].localize(l))) message = form.cleaned_data['message'].localize(l) preview_text = message.format( order='ORDER1234', event=self.request.event.name, order_date=date_format(now(), 'SHORT_DATE_FORMAT'), due_date=date_format(now() + timedelta(days=7), 'SHORT_DATE_FORMAT'), order_url=build_absolute_uri(self.request.event, 'presale:event.order', kwargs={ 'order': 'ORDER1234', 'secret': 'longrandomsecretabcdef123456' })) self.output[l].append(preview_text) return self.get(self.request, *self.args, **self.kwargs) else: try: with language(o.locale): mail(o.email, form.cleaned_data['subject'], form.cleaned_data['message'], { 'event': o.event, 'order': o.code, 'order_date': date_format(o.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'), 'due_date': date_format(o.expires, 'SHORT_DATE_FORMAT'), 'order_url': build_absolute_uri(o.event, 'presale:event.order', kwargs={ 'order': o.code, 'secret': o.secret })}, self.request.event, locale=o.locale, order=o) except SendMailException: failures.append(o.email) if failures: messages.error(self.request, _('Failed to send mails to the following users: {}'.format(' '.join(failures)))) else: messages.success(self.request, _('Your message has been queued to be sent to the selected users.')) return redirect( 'plugins:sendmail:send', event=self.request.event.slug, organizer=self.request.event.organizer.slug )
def test_sendmail_placeholder(env): djmail.outbox = [] event, user, organizer = env mail('*****@*****.**', '{event} Test subject', 'mailtest.txt', {"event": event}, event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Dummy Test subject'
def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None, force: bool=False, send_mail: bool=True, user: User=None) -> Order: """ Marks an order as paid. This sets the payment provider, info and date and returns the 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 :param send_mail: Whether an email should be sent to the user about this event (default: ``True``). :type send_mail: boolean :param user: The user that performed the change :raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False`` """ with order.event.lock(): can_be_paid = order._can_be_paid() if not force and can_be_paid is not True: raise Quota.QuotaExceededException(can_be_paid) 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.log_action('pretix.event.order.paid', { 'provider': provider, 'info': info, 'date': date, 'manual': manual, 'force': force }, user=user) order_paid.send(order.event, order=order) if send_mail: with language(order.locale): mail( order.email, _('Payment received for your order: %(code)s') % {'code': order.code}, order.event.settings.mail_text_order_paid, { 'event': order.event.name, 'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'downloads': order.event.settings.get('ticket_download', as_type=bool) }, order.event, locale=order.locale ) return order
def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None, force: bool=False, send_mail: bool=True, user: User=None) -> Order: """ Marks an order as paid. This sets the payment provider, info and date and returns the 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 :param send_mail: Whether an email should be sent to the user about this event (default: ``True``). :type send_mail: boolean :param user: The user that performed the change :raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False`` """ with order.event.lock() as now_dt: can_be_paid = order._can_be_paid() if not force and can_be_paid is not True: raise Quota.QuotaExceededException(can_be_paid) order.payment_provider = provider or order.payment_provider order.payment_info = info or order.payment_info order.payment_date = date or now_dt if manual is not None: order.payment_manual = manual order.status = Order.STATUS_PAID order.save() order.log_action('pretix.event.order.paid', { 'provider': provider, 'info': info, 'date': date, 'manual': manual, 'force': force }, user=user) order_paid.send(order.event, order=order) if send_mail: with language(order.locale): mail( order.email, _('Payment received for your order: %(code)s') % {'code': order.code}, order.event.settings.mail_text_order_paid, { 'event': order.event.name, 'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'downloads': order.event.settings.get('ticket_download', as_type=bool) }, order.event, locale=order.locale ) return order
def send_voucher(self, quota_cache=None, user=None, auth=None): availability = ( self.variation.check_quotas(count_waitinglist=False, subevent=self.subevent, _cache=quota_cache) if self.variation else self.item.check_quotas(count_waitinglist=False, subevent=self.subevent, _cache=quota_cache) ) if availability[1] is None or availability[1] < 1: raise WaitingListException(_('This product is currently not available.')) if self.voucher: raise WaitingListException(_('A voucher has already been sent to this person.')) if '@' not in self.email: raise WaitingListException(_('This entry is anonymized and can no longer be used.')) with transaction.atomic(): v = Voucher.objects.create( event=self.event, max_usages=1, valid_until=now() + timedelta(hours=self.event.settings.waiting_list_hours), item=self.item, variation=self.variation, tag='waiting-list', comment=_('Automatically created from waiting list entry for {email}').format( email=self.email ), block_quota=True, subevent=self.subevent, ) v.log_action('pretix.voucher.added.waitinglist', { 'item': self.item.pk, 'variation': self.variation.pk if self.variation else None, 'tag': 'waiting-list', 'block_quota': True, 'valid_until': v.valid_until.isoformat(), 'max_usages': 1, 'email': self.email, 'waitinglistentry': self.pk, 'subevent': self.subevent.pk if self.subevent else None, }, user=user, auth=auth) self.log_action('pretix.waitinglist.voucher', user=user, auth=auth) self.voucher = v self.save() with language(self.locale): mail( self.email, _('You have been selected from the waitinglist for {event}').format(event=str(self.event)), self.event.settings.mail_text_waiting_list, { 'event': self.event.name, 'url': build_absolute_uri(self.event, 'presale:event.redeem') + '?voucher=' + self.voucher.code, 'code': self.voucher.code, 'product': str(self.item) + (' - ' + str(self.variation) if self.variation else ''), 'hours': self.event.settings.waiting_list_hours, }, self.event, locale=self.locale )
def _perform_order(event: str, payment_provider: str, position_ids: List[str], email: str, locale: str, address: int): event = Event.objects.get(id=event) responses = register_payment_providers.send(event) pprov = None for rec, 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.filter( id__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) if address is not None: try: addr = InvoiceAddress.objects.get( pk=address ) if addr.order is not None: addr.pk = None addr.order = order addr.save() except InvoiceAddress.DoesNotExist: pass if event.settings.get('invoice_generate') == 'True': generate_invoice(order) with language(order.locale): mail( order.email, _('Your order: %(code)s') % {'code': order.code}, event.settings.mail_text_order_placed, { 'total': LazyNumber(order.total), 'currency': event.currency, 'date': LazyDate(order.expires), 'event': event.name, 'url': build_absolute_uri(event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'paymentinfo': str(pprov.order_pending_mail_render(order)) }, event, locale=order.locale ) return order.id
def test_send_mail_with_prefix(env): djmail.outbox = [] event, user, organizer = env event.settings.set('mail_prefix', 'test') mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == '[test] Test subject'
def test_send_mail_with_event_signature(env): djmail.outbox = [] event, user, organizer = env event.settings.set('mail_text_signature', 'This is a test signature.') mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert 'This is a test signature.' in djmail.outbox[0].body
def test_send_mail_with_event_sender(env): djmail.outbox = [] event, user, organizer = env event.settings.set('mail_from', 'foo@bar') mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Test subject'
def mark_order_paid(order: Order, provider: str = None, info: str = None, date: datetime = None, manual: bool = None, force: bool = 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`` """ with order.event.lock(): can_be_paid = order._can_be_paid() 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) mail(order.email, _('Payment received for your order: %(code)s') % {'code': order.code}, 'pretixpresale/email/order_paid.txt', { 'order': order, 'event': order.event, 'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'downloads': order.event.settings.get('ticket_download', as_type=bool) }, order.event, locale=order.locale) return order
def test_send_mail_with_default_sender(env): djmail.outbox = [] event, user, organizer = env mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) del event.settings['mail_from'] assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Test subject' assert djmail.outbox[0].from_email == settings.MAIL_FROM
def test_send_mail_with_event_sender(env): djmail.outbox = [] event, user, organizer = env event.settings.set('mail_from', 'foo@bar') mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Test subject' assert djmail.outbox[0].from_email == 'foo@bar'
def test_send_mail_with_default_sender(env): djmail.outbox = [] event, user, organizer = env mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event) del event.settings['mail_from'] assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Test subject' assert djmail.outbox[0].from_email == 'Dummy <%s>' % settings.MAIL_FROM
def test_send_mail_custom_event_smtp(env, smtp_use_custom): djmail.outbox = [] event, user, organizer = env event.settings.set("smtp_use_custom", smtp_use_custom) mail('*****@*****.**', 'Test subject', 'mailtest.txt', {}, event=event) assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [user.email] assert djmail.outbox[0].subject == 'Test subject'
def send_voucher(self, quota_cache=None, user=None, api_token=None): availability = ( self.variation.check_quotas(count_waitinglist=False, subevent=self.subevent, _cache=quota_cache) if self.variation else self.item.check_quotas(count_waitinglist=False, subevent=self.subevent, _cache=quota_cache) ) if availability[1] is None or availability[1] < 1: raise WaitingListException(_('This product is currently not available.')) if self.voucher: raise WaitingListException(_('A voucher has already been sent to this person.')) with transaction.atomic(): v = Voucher.objects.create( event=self.event, max_usages=1, valid_until=now() + timedelta(hours=self.event.settings.waiting_list_hours), item=self.item, variation=self.variation, tag='waiting-list', comment=_('Automatically created from waiting list entry for {email}').format( email=self.email ), block_quota=True, subevent=self.subevent, ) v.log_action('pretix.voucher.added.waitinglist', { 'item': self.item.pk, 'variation': self.variation.pk if self.variation else None, 'tag': 'waiting-list', 'block_quota': True, 'valid_until': v.valid_until.isoformat(), 'max_usages': 1, 'email': self.email, 'waitinglistentry': self.pk, 'subevent': self.subevent.pk if self.subevent else None, }, user=user, api_token=api_token) self.log_action('pretix.waitinglist.voucher', user=user, api_token=api_token) self.voucher = v self.save() with language(self.locale): mail( self.email, _('You have been selected from the waitinglist for {event}').format(event=str(self.event)), self.event.settings.mail_text_waiting_list, { 'event': self.event.name, 'url': build_absolute_uri(self.event, 'presale:event.redeem') + '?voucher=' + self.voucher.code, 'code': self.voucher.code, 'product': str(self.item) + (' - ' + str(self.variation) if self.variation else ''), 'hours': self.event.settings.waiting_list_hours, }, self.event, locale=self.locale )
def test_send_mail_with_user_locale(env): djmail.outbox = [] event, user, organizer = env user.locale = 'de' user.save() mail('*****@*****.**', _('User'), 'mailtest.txt', {}, event, locale=user.locale) del event.settings['mail_from'] assert len(djmail.outbox) == 1 assert djmail.outbox[0].subject == 'Benutzer' assert 'The language code used for rendering this e-mail is de.' in djmail.outbox[0].body
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
def send_expiry_warnings(sender, **kwargs): eventcache = {} today = now().replace(hour=0, minute=0, second=0) for o in Order.objects.filter( expires__gte=today, expiry_reminder_sent=False, status=Order.STATUS_PENDING).select_related('event'): eventsettings = eventcache.get(o.event.pk, None) if eventsettings is None: eventsettings = o.event.settings eventcache[o.event.pk] = eventsettings days = eventsettings.get('mail_days_order_expire_warning', as_type=int) tz = pytz.timezone(eventsettings.get('timezone', settings.TIME_ZONE)) if days and (o.expires - today).days <= days: o.expiry_reminder_sent = True o.save() 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): mail(o.email, _('Your order is about to expire: %(code)s') % {'code': o.code}, eventsettings.mail_text_order_expire_warning, { 'event': o.event.name, 'url': build_absolute_uri(o.event, 'presale:event.order', kwargs={ 'order': o.code, 'secret': o.secret }), 'expire_date': date_format(o.expires.astimezone(tz), 'SHORT_DATE_FORMAT'), 'invoice_name': invoice_name, 'invoice_company': invoice_company, }, o.event, locale=o.locale) except SendMailException: logger.exception('Reminder email could not be sent') else: o.log_action('pretix.event.order.expire_warning_sent')
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 )
def _perform_order(event: str, payment_provider: str, position_ids: List[str], email: str, locale: str): event = Event.objects.get(id=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.filter(id__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}, event.settings.mail_text_order_placed, { 'total': LazyNumber(order.total), 'currency': event.currency, 'date': LazyDate(order.expires), 'event': event.name, 'url': build_absolute_uri(event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'paymentinfo': str(pprov.order_pending_mail_render(order)) }, event, locale=order.locale) return order.id
def _notify_user(self): with language(self.order.locale): mail( self.order.email, _('Your order has been changed: %(code)s') % {'code': self.order.code}, self.order.event.settings.mail_text_order_changed, { 'event': self.order.event.name, 'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={ 'order': self.order.code, 'secret': self.order.secret }), }, self.order.event, locale=self.order.locale )
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).format_map(email_context), 'message': message.localize(o.locale).format_map(email_context), 'recipient': o.email } ) except SendMailException: failures.append(o.email)
def _perform_order(event: str, payment_provider: str, position_ids: List[str], email: str, locale: str, address: int): event = Event.objects.get(id=event) responses = register_payment_providers.send(event) pprov = None for rec, response in responses: provider = response(event) if provider.identifier == payment_provider: pprov = provider if not pprov: raise OrderError(error_messages['internal']) with event.lock() as now_dt: positions = list(CartPosition.objects.filter( id__in=position_ids).select_related('item', 'variation')) if len(position_ids) != len(positions): raise OrderError(error_messages['internal']) _check_positions(event, now_dt, positions) order = _create_order(event, email, positions, now_dt, pprov, locale=locale, address=address) if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order): if not order.invoices.exists(): generate_invoice(order) with language(order.locale): if order.total == Decimal('0.00'): mailtext = event.settings.mail_text_order_free else: mailtext = event.settings.mail_text_order_placed mail( order.email, _('Your order: %(code)s') % {'code': order.code}, mailtext, { 'total': LazyNumber(order.total), 'currency': event.currency, 'date': LazyDate(order.expires), 'event': event.name, 'url': build_absolute_uri(event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'paymentinfo': str(pprov.order_pending_mail_render(order)) }, event, locale=order.locale ) return order.id
def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent): with language(wle.locale, wle.event.settings.region): email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event) try: mail(wle.email, str(subject).format_map(TolerantDict(email_context)), message, email_context, wle.event, locale=wle.locale) except SendMailException: logger.exception('Waiting list canceled email could not be sent')
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)
def form_valid(self, form): orders = Order.objects.filter(event=self.request.event, status__in=form.cleaned_data["sendto"]) mails = set([(o.email, o.locale) for o in orders]) self.request.event.log_action( "pretix.plugins.sendmail.sent", user=self.request.user, data=dict(form.cleaned_data) ) for m, l in mails: mail(m, form.cleaned_data["subject"], form.cleaned_data["message"], None, self.request.event, locale=l) messages.success(self.request, _("Your message will be sent to the selected users.")) return redirect( "plugins:sendmail:send", event=self.request.event.slug, organizer=self.request.event.organizer.slug )
def form_valid(self, form): orders = Order.objects.current.filter( event=self.request.event, status__in=form.cleaned_data['sendto'] ).select_related("user") users = set([o.user for o in orders]) for u in users: mail(u, form.cleaned_data['subject'], form.cleaned_data['message'], None, self.request.event) messages.success(self.request, _('Your message will be sent to the selected users.')) return redirect( 'plugins:sendmail:send', event=self.request.event.slug, organizer=self.request.event.organizer.slug )
def post(self, *args, **kwargs): with language(self.order.locale): mail( self.order.email, _('Your order: %(code)s') % {'code': self.order.code}, self.order.event.settings.mail_text_resend_link, { 'event': self.order.event.name, 'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={ 'order': self.order.code, 'secret': self.order.secret }), }, self.order.event, locale=self.order.locale ) messages.success(self.request, _('The email has been queued to be sent.')) self.order.log_action('pretix.event.order.resend', user=self.request.user) return redirect(self.get_order_url())
def post(self, request, *args, **kwargs): if not self.link_form.is_valid(): messages.error(self.request, _('We had difficulties processing your input.')) return self.get(request, *args, **kwargs) user = self.link_form.cleaned_data.get('email') if settings.HAS_REDIS: from django_redis import get_redis_connection rc = get_redis_connection("redis") if rc.exists('pretix_resend_{}'.format(user)): messages.error(request, _('We already sent you an email in the last 24 hours.')) return redirect(eventreverse(self.request.event, 'presale:event.resend_link')) else: rc.setex('pretix_resend_{}'.format(user), 3600 * 24, '1') orders = self.request.event.orders.filter(email__iexact=user) order_context = [] for order in orders: url = build_absolute_uri( self.request.event, 'presale:event.order', kwargs={'order': order.code, 'secret': order.secret} ) order_context.append(' - {} - {}'.format(order, url)) if not orders: user = INVALID_ADDRESS subject = _('Your orders for {}'.format(self.request.event)) template = self.request.event.settings.mail_text_resend_all_links context = { 'orders': '\n'.join(order_context), 'event': self.request.event, } try: mail(user, subject, template, context, event=self.request.event, locale=self.request.LANGUAGE_CODE) except SendMailException: logger = logging.getLogger('pretix.presale.user') logger.exception('A mail resending order links to {} could not be sent.'.format(user)) messages.error(self.request, _('We have trouble sending emails right now, please check back later.')) return self.get(request, *args, **kwargs) messages.success(self.request, _('If there were any orders by this user, they will receive an email with their order codes.')) return redirect(eventreverse(self.request.event, 'presale:event.index'))
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')}, )
def _perform_order(event: str, payment_provider: str, 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(event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret }), 'payment': pprov.order_pending_mail_render(order) }, event, locale=order.locale) return order.identity
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
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
def form_valid(self, form): orders = Order.objects.current.filter( event=self.request.event, status__in=form.cleaned_data["sendto"] ).select_related("user") users = set([o.user for o in orders]) for u in users: mail( u.email, form.cleaned_data["subject"], form.cleaned_data["message"], None, self.request.event, locale=u.locale, ) messages.success(self.request, _("Your message will be sent to the selected users.")) return redirect( "plugins:sendmail:send", event=self.request.event.slug, organizer=self.request.event.organizer.slug )
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') }, )
def form_valid(self, form): qs = Order.objects.filter(event=self.request.event) statusq = Q(status__in=form.cleaned_data['sendto']) if 'overdue' in form.cleaned_data['sendto']: statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now()) orders = qs.filter(statusq) self.request.event.log_action('pretix.plugins.sendmail.sent', user=self.request.user, data=dict( form.cleaned_data)) for o in orders: mail(o.email, form.cleaned_data['subject'], form.cleaned_data['message'], None, self.request.event, locale=o.locale, order=o) messages.success(self.request, _('Your message will be sent to the selected users.')) return redirect( 'plugins:sendmail:send', event=self.request.event.slug, organizer=self.request.event.organizer.slug )