import re
from collections import OrderedDict
from datetime import timedelta

from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.files import File
from django.core.urlresolvers import reverse
from django.db import transaction
from django.forms import modelformset_factory
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils import translation
from django.utils.formats import date_format
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, ListView
from django.views.generic.base import TemplateView, View
from django.views.generic.detail import SingleObjectMixin
from pytz import timezone

from pretix.base.forms import I18nModelForm
from pretix.base.models import (
    CachedTicket, Event, EventPermission, Item, ItemVariation, LogEntry, Order,
    RequiredAction, User, Voucher,
)
from pretix.base.services import tickets
from pretix.base.services.invoices import build_preview_invoice_pdf
from pretix.base.services.mail import SendMailException, mail
from pretix.base.signals import (
    event_live_issues, register_payment_providers, register_ticket_outputs,
)
from pretix.control.forms.event import (
    DisplaySettingsForm, EventSettingsForm, EventUpdateForm,
    InvoiceSettingsForm, MailSettingsForm, PaymentSettingsForm, ProviderForm,
    TicketSettingsForm,
)
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.helpers.urls import build_absolute_uri
from pretix.presale.style import regenerate_css

from . import UpdateView
from ..logdisplay import OVERVIEW_BLACKLIST


class EventUpdate(EventPermissionRequiredMixin, UpdateView):
    model = Event
    form_class = EventUpdateForm
    template_name = 'pretixcontrol/event/settings.html'
    permission = 'can_change_settings'

    @cached_property
    def object(self) -> Event:
        return self.request.event

    def get_object(self, queryset=None) -> Event:
        return self.object

    @cached_property
    def sform(self):
        return EventSettingsForm(
            obj=self.object,
            prefix='settings',
            data=self.request.POST if self.request.method == 'POST' else None
        )

    def get_context_data(self, *args, **kwargs) -> dict:
        context = super().get_context_data(*args, **kwargs)
        context['sform'] = self.sform
        return context

    @transaction.atomic
    def form_valid(self, form):
        self.sform.save()
        if self.sform.has_changed():
            self.request.event.log_action('pretix.event.settings', user=self.request.user, data={
                k: self.request.event.settings.get(k) for k in self.sform.changed_data
            })
        if form.has_changed():
            self.request.event.log_action('pretix.event.changed', user=self.request.user, data={
                k: getattr(self.request.event, k) for k in form.changed_data
            })
        messages.success(self.request, _('Your changes have been saved.'))
        return super().form_valid(form)

    def get_success_url(self) -> str:
        return reverse('control:event.settings', kwargs={
            'organizer': self.object.organizer.slug,
            'event': self.object.slug,
        })

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid() and self.sform.is_valid():
            # reset timezone
            zone = timezone(self.sform.cleaned_data['timezone'])
            event = form.instance
            event.date_from = self.reset_timezone(zone, event.date_from)
            event.date_to = self.reset_timezone(zone, event.date_to)
            event.presale_start = self.reset_timezone(zone, event.presale_start)
            event.presale_end = self.reset_timezone(zone, event.presale_end)
            return self.form_valid(form)
        else:
            messages.error(self.request, _('We could not save your changes. See below for details.'))
            return self.form_invalid(form)

    @staticmethod
    def reset_timezone(tz, dt):
        return tz.localize(dt.replace(tzinfo=None)) if dt is not None else None


class EventPlugins(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
    model = Event
    context_object_name = 'event'
    permission = 'can_change_settings'
    template_name = 'pretixcontrol/event/plugins.html'

    def get_object(self, queryset=None) -> Event:
        return self.request.event

    def get_context_data(self, *args, **kwargs) -> dict:
        from pretix.base.plugins import get_all_plugins

        context = super().get_context_data(*args, **kwargs)
        context['plugins'] = [p for p in get_all_plugins() if not p.name.startswith('.')
                              and getattr(p, 'visible', True)]
        context['plugins_active'] = self.object.get_plugins()
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        from pretix.base.plugins import get_all_plugins

        self.object = self.get_object()

        plugins_active = self.object.get_plugins()
        plugins_available = {
            p.module: p for p in get_all_plugins()
            if not p.name.startswith('.') and getattr(p, 'visible', True)
        }

        with transaction.atomic():
            for key, value in request.POST.items():
                if key.startswith("plugin:"):
                    module = key.split(":")[1]
                    if value == "enable" and module in plugins_available:
                        if getattr(plugins_available[module], 'restricted', False):
                            if not request.user.is_superuser:
                                continue
                        self.request.event.log_action('pretix.event.plugins.enabled', user=self.request.user,
                                                      data={'plugin': module})
                        if module not in plugins_active:
                            plugins_active.append(module)
                    else:
                        self.request.event.log_action('pretix.event.plugins.disabled', user=self.request.user,
                                                      data={'plugin': module})
                        if module in plugins_active:
                            plugins_active.remove(module)
            self.object.plugins = ",".join(plugins_active)
            self.object.save()
        messages.success(self.request, _('Your changes have been saved.'))
        return redirect(self.get_success_url())

    def get_success_url(self) -> str:
        return reverse('control:event.settings.plugins', kwargs={
            'organizer': self.get_object().organizer.slug,
            'event': self.get_object().slug,
        })


class PaymentSettings(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
    model = Event
    context_object_name = 'event'
    permission = 'can_change_settings'
    template_name = 'pretixcontrol/event/payment.html'

    def get_object(self, queryset=None) -> Event:
        return self.request.event

    @cached_property
    def provider_forms(self) -> list:
        providers = []
        responses = register_payment_providers.send(self.request.event)
        for receiver, response in responses:
            provider = response(self.request.event)
            provider.form = ProviderForm(
                obj=self.request.event,
                settingspref='payment_%s_' % provider.identifier,
                data=(self.request.POST if self.request.method == 'POST' else None)
            )
            provider.form.fields = OrderedDict(
                [
                    ('payment_%s_%s' % (provider.identifier, k), v)
                    for k, v in provider.settings_form_fields.items()
                ]
            )
            provider.settings_content = provider.settings_content_render(self.request)
            provider.form.prepare_fields()
            if provider.settings_content or provider.form.fields:
                # Exclude providers which do not provide any settings
                providers.append(provider)
        return providers

    def get_context_data(self, *args, **kwargs) -> dict:
        context = super().get_context_data(*args, **kwargs)
        context['sform'] = self.sform
        return context

    @cached_property
    def sform(self):
        return PaymentSettingsForm(
            obj=self.object,
            prefix='settings',
            data=self.request.POST if self.request.method == 'POST' else None
        )

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        context['providers'] = self.provider_forms
        return self.render_to_response(context)

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        success = self.sform.is_valid()
        if success:
            self.sform.save()
            if self.sform.has_changed():
                self.request.event.log_action('pretix.event.settings', user=self.request.user, data={
                    k: self.request.event.settings.get(k) for k in self.sform.changed_data
                })
        for provider in self.provider_forms:
            if provider.form.is_valid():
                if provider.form.has_changed():
                    self.request.event.log_action(
                        'pretix.event.payment.provider.' + provider.identifier, user=self.request.user, data={
                            k: provider.form.cleaned_data.get(k) for k in provider.form.changed_data
                        }
                    )
                provider.form.save()
            else:
                success = False
        if success:
            messages.success(self.request, _('Your changes have been saved.'))
            return redirect(self.get_success_url())
        else:
            messages.error(self.request, _('We could not save your changes. See below for details.'))
            return self.get(request)

    def get_success_url(self) -> str:
        return reverse('control:event.settings.payment', kwargs={
            'organizer': self.get_object().organizer.slug,
            'event': self.get_object().slug,
        })


class EventSettingsFormView(EventPermissionRequiredMixin, FormView):
    model = Event
    permission = 'can_change_settings'

    def get_context_data(self, *args, **kwargs) -> dict:
        context = super().get_context_data(*args, **kwargs)
        return context

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['obj'] = self.request.event
        return kwargs

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid():
            form.save()
            if form.has_changed():
                self.request.event.log_action(
                    'pretix.event.settings', user=self.request.user, data={
                        k: (form.cleaned_data.get(k).name
                            if isinstance(form.cleaned_data.get(k), File)
                            else form.cleaned_data.get(k))
                        for k in form.changed_data
                    }
                )
            messages.success(self.request, _('Your changes have been saved.'))
            return redirect(self.get_success_url())
        else:
            messages.error(self.request, _('We could not save your changes. See below for details.'))
            return self.get(request)


class InvoiceSettings(EventSettingsFormView):
    model = Event
    form_class = InvoiceSettingsForm
    template_name = 'pretixcontrol/event/invoicing.html'
    permission = 'can_change_settings'

    def get_success_url(self) -> str:
        if 'preview' in self.request.POST:
            return reverse('control:event.settings.invoice.preview', kwargs={
                'organizer': self.request.event.organizer.slug,
                'event': self.request.event.slug
            })
        return reverse('control:event.settings.invoice', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })


class InvoicePreview(EventPermissionRequiredMixin, View):
    permission = 'can_change_settings'

    def get(self, request, *args, **kwargs):
        pdf = build_preview_invoice_pdf(request.event)
        resp = HttpResponse(pdf, content_type='application/pdf')
        resp['Content-Disposition'] = 'attachment; filename="invoice-preview.pdf"'
        return resp


class DisplaySettings(EventSettingsFormView):
    model = Event
    form_class = DisplaySettingsForm
    template_name = 'pretixcontrol/event/display.html'
    permission = 'can_change_settings'

    def get_success_url(self) -> str:
        return reverse('control:event.settings.display', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid():
            form.save()
            if form.has_changed():
                self.request.event.log_action(
                    'pretix.event.settings', user=self.request.user, data={
                        k: (form.cleaned_data.get(k).name
                            if isinstance(form.cleaned_data.get(k), File)
                            else form.cleaned_data.get(k))
                        for k in form.changed_data
                    }
                )
            regenerate_css.apply_async(args=(self.request.event.pk,))
            messages.success(self.request, _('Your changes have been saved. Please note that it can '
                                             'take a short period of time until your changes become '
                                             'active.'))
            return redirect(self.get_success_url())
        else:
            messages.error(self.request, _('We could not save your changes. See below for details.'))
            return self.get(request)


class MailSettings(EventSettingsFormView):
    model = Event
    form_class = MailSettingsForm
    template_name = 'pretixcontrol/event/mail.html'
    permission = 'can_change_settings'

    def get_success_url(self) -> str:
        return reverse('control:event.settings.mail', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid():
            form.save()
            if form.has_changed():
                self.request.event.log_action(
                    'pretix.event.settings', user=self.request.user, data={
                        k: form.cleaned_data.get(k) for k in form.changed_data
                    }
                )

            if request.POST.get('test', '0').strip() == '1':
                backend = self.request.event.get_mail_backend(force_custom=True)
                try:
                    backend.test(self.request.event.settings.mail_from)
                except Exception as e:
                    messages.warning(self.request, _('An error occured while contacting the SMTP server: %s') % str(e))
                else:
                    if form.cleaned_data.get('smtp_use_custom'):
                        messages.success(self.request, _('Your changes have been saved and the connection attempt to '
                                                         'your SMTP server was successful.'))
                    else:
                        messages.success(self.request, _('We\'ve been able to contact the SMTP server you configured. '
                                                         'Remember to check the "use custom SMTP server" checkbox, '
                                                         'otherwise your SMTP server will not be used.'))
            else:
                messages.success(self.request, _('Your changes have been saved.'))
            return redirect(self.get_success_url())
        else:
            messages.error(self.request, _('We could not save your changes. See below for details.'))
            return self.get(request)


class MailSettingsPreview(EventPermissionRequiredMixin, View):
    permission = 'can_change_settings'

    # return the origin text if key is missing in dict
    class SafeDict(dict):
        def __missing__(self, key):
            return '{' + key + '}'

    @staticmethod
    def generate_order_fullname(slug, code):
        return '{event}-{code}'.format(event=slug.upper(), code=code)

    # create data which depend on locale
    def localized_data(self):
        return {
            'date': date_format(now() + timedelta(days=7), 'SHORT_DATE_FORMAT'),
            'expire_date': date_format(now() + timedelta(days=15), 'SHORT_DATE_FORMAT'),
            'payment_info': _('{} {} has been transferred to account <9999-9999-9999-9999> at {}').format(
                42.23, self.request.event.currency, date_format(now(), 'SHORT_DATETIME_FORMAT'))
        }

    # create index-language mapping
    @cached_property
    def supported_locale(self):
        locales = {}
        for idx, val in enumerate(settings.LANGUAGES):
            if val[0] in self.request.event.settings.locales:
                locales[str(idx)] = val[0]
        return locales

    @cached_property
    def items(self):
        return {
            'mail_text_order_placed': ['total', 'currency', 'date', 'invoice_company',
                                       'event', 'paymentinfo', 'url', 'invoice_name'],
            'mail_text_order_paid': ['event', 'url', 'invoice_name', 'invoice_company', 'payment_info'],
            'mail_text_order_free': ['event', 'url', 'invoice_name', 'invoice_company'],
            'mail_text_resend_link': ['event', 'url', 'invoice_name', 'invoice_company'],
            'mail_text_resend_all_links': ['event', 'orders'],
            'mail_text_order_changed': ['event', 'url', 'invoice_name', 'invoice_company'],
            'mail_text_order_expire_warning': ['event', 'url', 'expire_date', 'invoice_name', 'invoice_company'],
            'mail_text_waiting_list': ['event', 'url', 'product', 'hours', 'code']
        }

    @cached_property
    def base_data(self):
        user_orders = [
            {'code': 'F8VVL', 'secret': '6zzjnumtsx136ddy'},
            {'code': 'HIDHK', 'secret': '98kusd8ofsj8dnkd'},
            {'code': 'OPKSB', 'secret': '09pjdksflosk3njd'}
        ]
        orders = [' - {} - {}'.format(self.generate_order_fullname(self.request.event.slug, order['code']),
                                      self.generate_order_url(order['code'], order['secret']))
                  for order in user_orders]
        return {
            'event': self.request.event.name,
            'total': 42.23,
            'currency': self.request.event.currency,
            'url': self.generate_order_url(user_orders[0]['code'], user_orders[0]['secret']),
            'orders': '\n'.join(orders),
            'hours': self.request.event.settings.waiting_list_hours,
            'product': _('Sample Admission Ticket'),
            'code': '68CYU2H6ZTP3WLK5',
            'invoice_name': _('John Doe'),
            'invoice_company': _('Sample Corporation'),
            'paymentinfo': _('Please transfer money to this bank account: 9999-9999-9999-9999')
        }

    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
        })

    # get all supported placeholders with dummy values
    def placeholders(self, item):
        supported = {}
        local_data = self.localized_data()
        for key in self.items.get(item):
            supported[key] = self.base_data.get(key) if key in self.base_data else local_data.get(key)
        return self.SafeDict(supported)

    def post(self, request, *args, **kwargs):
        preview_item = request.POST.get('item', '')
        if preview_item not in self.items:
            return HttpResponseBadRequest(_('invalid item'))

        regex = r"^" + re.escape(preview_item) + r"_(?P<idx>[\d+])$"
        msgs = {}
        for k, v in request.POST.items():
            # only accept allowed fields
            matched = re.search(regex, k)
            if matched is not None:
                idx = matched.group('idx')
                if idx in self.supported_locale:
                    with translation.override(self.supported_locale[idx]):
                        msgs[self.supported_locale[idx]] = v.format_map(self.placeholders(preview_item))

        return JsonResponse({
            'item': preview_item,
            'msgs': msgs
        })


class TicketSettingsPreview(EventPermissionRequiredMixin, View):
    permission = 'can_change_settings'

    @cached_property
    def output(self):
        responses = register_ticket_outputs.send(self.request.event)
        for receiver, response in responses:
            provider = response(self.request.event)
            if provider.identifier == self.kwargs.get('output'):
                return provider

    def get(self, request, *args, **kwargs):
        if not self.output:
            messages.error(request, _('You requested an invalid ticket output type.'))
            return redirect(self.get_error_url())

        fname, mimet, data = tickets.preview(self.request.event.pk, self.output.identifier)
        resp = HttpResponse(data, content_type=mimet)
        ftype = fname.split(".")[-1]
        resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
        return resp

    def get_error_url(self) -> str:
        return reverse('control:event.settings.tickets', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })


class TicketSettings(EventPermissionRequiredMixin, FormView):
    model = Event
    form_class = TicketSettingsForm
    template_name = 'pretixcontrol/event/tickets.html'
    permission = 'can_change_settings'

    def get_context_data(self, *args, **kwargs) -> dict:
        context = super().get_context_data(*args, **kwargs)
        context['providers'] = self.provider_forms
        return context

    def get_success_url(self) -> str:
        return reverse('control:event.settings.tickets', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['obj'] = self.request.event
        return kwargs

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        form.prepare_fields()
        return form

    def form_invalid(self, form):
        messages.error(self.request, _('We could not save your changes. See below for details.'))
        return super().form_invalid(form)

    @transaction.atomic
    def post(self, request, *args, **kwargs):
        success = True
        for provider in self.provider_forms:
            if provider.form.is_valid():
                provider.form.save()
                if provider.form.has_changed():
                    self.request.event.log_action(
                        'pretix.event.tickets.provider.' + provider.identifier, user=self.request.user, data={
                            k: (provider.form.cleaned_data.get(k).name
                                if isinstance(provider.form.cleaned_data.get(k), File)
                                else provider.form.cleaned_data.get(k))
                            for k in provider.form.changed_data
                        }
                    )
                    CachedTicket.objects.filter(
                        order_position__order__event=self.request.event, provider=provider.identifier
                    ).delete()
            else:
                success = False
        form = self.get_form(self.get_form_class())
        if success and form.is_valid():
            form.save()
            if form.has_changed():
                self.request.event.log_action(
                    'pretix.event.tickets.settings', user=self.request.user, data={
                        k: form.cleaned_data.get(k) for k in form.changed_data
                    }
                )
            messages.success(self.request, _('Your changes have been saved.'))
            return redirect(self.get_success_url())
        else:
            return self.form_invalid(form)

    @cached_property
    def provider_forms(self) -> list:
        providers = []
        responses = register_ticket_outputs.send(self.request.event)
        for receiver, response in responses:
            provider = response(self.request.event)
            provider.form = ProviderForm(
                obj=self.request.event,
                settingspref='ticketoutput_%s_' % provider.identifier,
                data=(self.request.POST if self.request.method == 'POST' else None),
                files=(self.request.FILES if self.request.method == 'POST' else None)
            )
            provider.form.fields = OrderedDict(
                [
                    ('ticketoutput_%s_%s' % (provider.identifier, k), v)
                    for k, v in provider.settings_form_fields.items()
                ]
            )
            provider.settings_content = provider.settings_content_render(self.request)
            provider.form.prepare_fields()

            provider.preview_allowed = True
            for k, v in provider.settings_form_fields.items():
                if v.required and not self.request.event.settings.get('ticketoutput_%s_%s' % (provider.identifier, k)):
                    provider.preview_allowed = False
                    break

            providers.append(provider)
        return providers


class EventPermissionForm(I18nModelForm):
    class Meta:
        model = EventPermission
        fields = (
            'can_change_settings', 'can_change_items', 'can_change_permissions', 'can_view_orders',
            'can_change_orders', 'can_view_vouchers', 'can_change_vouchers'
        )


class EventPermissionCreateForm(EventPermissionForm):
    user = forms.EmailField(required=False, label=_('User'))


class EventPermissions(EventPermissionRequiredMixin, TemplateView):
    model = Event
    form_class = TicketSettingsForm
    template_name = 'pretixcontrol/event/permissions.html'
    permission = 'can_change_permissions'

    @cached_property
    def formset(self):
        fs = modelformset_factory(
            EventPermission,
            form=EventPermissionForm,
            can_delete=True, can_order=False, extra=0
        )
        return fs(data=self.request.POST if self.request.method == "POST" else None,
                  prefix="formset",
                  queryset=EventPermission.objects.filter(event=self.request.event))

    @cached_property
    def add_form(self):
        return EventPermissionCreateForm(data=self.request.POST if self.request.method == "POST" else None,
                                         prefix="add")

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['formset'] = self.formset
        ctx['add_form'] = self.add_form
        return ctx

    def _send_invite(self, instance):
        try:
            mail(
                instance.invite_email,
                _('pretix account invitation'),
                'pretixcontrol/email/invitation.txt',
                {
                    'user': self,
                    'event': self.request.event.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

    @transaction.atomic
    def post(self, *args, **kwargs):
        if self.formset.is_valid() and self.add_form.is_valid():
            if self.add_form.has_changed():
                logdata = {
                    k: v for k, v in self.add_form.cleaned_data.items()
                }

                try:
                    self.add_form.instance.event = self.request.event
                    self.add_form.instance.event_id = self.request.event.id
                    self.add_form.instance.user = User.objects.get(email=self.add_form.cleaned_data['user'])
                    self.add_form.instance.user_id = self.add_form.instance.user.id
                except User.DoesNotExist:
                    self.add_form.instance.invite_email = self.add_form.cleaned_data['user']
                    if EventPermission.objects.filter(invite_email=self.add_form.instance.invite_email,
                                                      event=self.request.event).exists():
                        messages.error(self.request, _('This user already has been invited for this event.'))
                        return self.get(*args, **kwargs)

                    self.add_form.save()
                    self._send_invite(self.add_form.instance)

                    self.request.event.log_action(
                        'pretix.event.permissions.invited', user=self.request.user, data=logdata
                    )
                else:
                    if EventPermission.objects.filter(user=self.add_form.instance.user,
                                                      event=self.request.event).exists():
                        messages.error(self.request, _('This user already has permissions for this event.'))
                        return self.get(*args, **kwargs)
                    self.add_form.save()
                    logdata['user'] = self.add_form.instance.user_id
                    self.request.event.log_action(
                        'pretix.event.permissions.added', user=self.request.user, data=logdata
                    )
            for form in self.formset.forms:
                if form.has_changed():
                    changedata = {
                        k: form.cleaned_data.get(k) for k in form.changed_data
                    }
                    changedata['user'] = form.instance.user_id
                    self.request.event.log_action(
                        'pretix.event.permissions.changed', user=self.request.user, data=changedata
                    )
                if form.instance.user_id == self.request.user.pk:
                    if not form.cleaned_data['can_change_permissions'] or form in self.formset.deleted_forms:
                        messages.error(self.request, _('You cannot remove your own permission to view this page.'))
                        return self.get(*args, **kwargs)

            for form in self.formset.deleted_forms:
                logdata = {
                    k: v for k, v in form.cleaned_data.items()
                }
                self.request.event.log_action(
                    'pretix.event.permissions.deleted', user=self.request.user, data=logdata
                )

            self.formset.save()
            messages.success(self.request, _('Your changes have been saved.'))
            return redirect(self.get_success_url())
        else:
            messages.error(self.request, _('Your changes could not be saved.'))
            return self.get(*args, **kwargs)

    def get_success_url(self) -> str:
        return reverse('control:event.settings.permissions', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })


class EventLive(EventPermissionRequiredMixin, TemplateView):
    permission = 'can_change_settings'
    template_name = 'pretixcontrol/event/live.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['issues'] = self.issues
        return ctx

    @cached_property
    def issues(self):
        issues = []
        has_paid_things = (
            Item.objects.filter(event=self.request.event, default_price__gt=0).exists()
            or ItemVariation.objects.filter(item__event=self.request.event, default_price__gt=0).exists()
        )

        has_payment_provider = False
        responses = register_payment_providers.send(self.request.event)
        for receiver, response in responses:
            provider = response(self.request.event)
            if provider.is_enabled and provider.identifier != 'free':
                has_payment_provider = True
                break

        if has_paid_things and not has_payment_provider:
            issues.append(_('You have configured at least one paid product but have not enabled any payment methods.'))

        if not self.request.event.quotas.exists():
            issues.append(_('You need to configure at least one quota to sell anything.'))

        responses = event_live_issues.send(self.request.event)
        for receiver, response in responses:
            if response:
                issues.append(response)

        return issues

    def post(self, request, *args, **kwargs):
        if request.POST.get("live") == "true" and not self.issues:
            request.event.live = True
            request.event.save()
            self.request.event.log_action(
                'pretix.event.live.activated', user=self.request.user, data={}
            )
            messages.success(self.request, _('Your shop is live now!'))
        elif request.POST.get("live") == "false":
            request.event.live = False
            request.event.save()
            self.request.event.log_action(
                'pretix.event.live.deactivated', user=self.request.user, data={}
            )
            messages.success(self.request, _('We\'ve taken your shop down. You can re-enable it whenever you want!'))
        return redirect(self.get_success_url())

    def get_success_url(self) -> str:
        return reverse('control:event.live', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })


class EventLog(EventPermissionRequiredMixin, ListView):
    template_name = 'pretixcontrol/event/logs.html'
    model = LogEntry
    context_object_name = 'logs'
    paginate_by = 20

    def get_queryset(self):
        qs = self.request.event.logentry_set.all().select_related('user', 'content_type').order_by('-datetime')
        qs = qs.exclude(action_type__in=OVERVIEW_BLACKLIST)
        if not self.request.eventperm.can_view_orders:
            qs = qs.exclude(content_type=ContentType.objects.get_for_model(Order))
        if not self.request.eventperm.can_view_vouchers:
            qs = qs.exclude(content_type=ContentType.objects.get_for_model(Voucher))

        if self.request.GET.get('user') == 'yes':
            qs = qs.filter(user__isnull=False)
        elif self.request.GET.get('user') == 'no':
            qs = qs.filter(user__isnull=True)
        elif self.request.GET.get('user'):
            qs = qs.filter(user_id=self.request.GET.get('user'))

        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        ctx['userlist'] = self.request.event.user_perms.select_related('user')
        return ctx


class EventActions(EventPermissionRequiredMixin, ListView):
    template_name = 'pretixcontrol/event/actions.html'
    model = RequiredAction
    context_object_name = 'actions'
    paginate_by = 20
    permission = 'can_change_orders'

    def get_queryset(self):
        qs = self.request.event.requiredaction_set.filter(done=False)
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()
        for a in ctx['actions']:
            a.display = a.display(self.request)
        return ctx


class EventActionDiscard(EventPermissionRequiredMixin, View):
    permission = 'can_change_orders'

    def get(self, request, **kwargs):
        action = get_object_or_404(RequiredAction, event=request.event, pk=kwargs.get('id'))
        action.done = True
        action.user = request.user
        action.save()
        messages.success(self.request, _('The issue has been marked as resolved!'))
        return redirect(self.get_success_url())

    def get_success_url(self) -> str:
        return reverse('control:event.index', kwargs={
            'organizer': self.request.event.organizer.slug,
            'event': self.request.event.slug
        })
