Reusable media (#3131)

Co-authored-by: Martin Gross <gross@rami.io>
This commit is contained in:
Raphael Michel
2023-04-03 10:45:22 +02:00
committed by GitHub
parent 377117548d
commit d0b449ea89
67 changed files with 2876 additions and 133 deletions

View File

@@ -367,7 +367,7 @@ class OrderDetail(OrderView):
'item', 'variation', 'addon_to', 'tax_rule', 'used_membership', 'used_membership__membership_type',
'discount',
).prefetch_related(
'item__questions', 'issued_gift_cards',
'item__questions', 'issued_gift_cards', 'linked_media',
Prefetch('answers', queryset=QuestionAnswer.objects.prefetch_related('options').select_related('question')),
Prefetch('all_checkins', queryset=Checkin.all.select_related('list').order_by('datetime')),
).order_by('positionid')

View File

@@ -73,7 +73,7 @@ from pretix.base.i18n import language
from pretix.base.models import (
CachedFile, Customer, Device, Gate, GiftCard, Invoice, LogEntry,
Membership, MembershipType, Order, OrderPayment, OrderPosition, Organizer,
ScheduledOrganizerExport, Team, TeamInvite, User,
ReusableMedium, ScheduledOrganizerExport, Team, TeamInvite, User,
)
from pretix.base.models.customers import CustomerSSOClient, CustomerSSOProvider
from pretix.base.models.event import Event, EventMetaProperty, EventMetaValue
@@ -92,7 +92,7 @@ from pretix.base.views.tasks import AsyncAction
from pretix.control.forms.exports import ScheduledOrganizerExportForm
from pretix.control.forms.filter import (
CustomerFilterForm, DeviceFilterForm, EventFilterForm, GiftCardFilterForm,
OrganizerFilterForm, TeamFilterForm,
OrganizerFilterForm, ReusableMediaFilterForm, TeamFilterForm,
)
from pretix.control.forms.orders import ExporterForm
from pretix.control.forms.organizer import (
@@ -100,8 +100,9 @@ from pretix.control.forms.organizer import (
EventMetaPropertyForm, GateForm, GiftCardCreateForm, GiftCardUpdateForm,
MailSettingsForm, MembershipTypeForm, MembershipUpdateForm,
OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerForm,
OrganizerSettingsForm, OrganizerUpdateForm, SSOClientForm, SSOProviderForm,
TeamForm, WebHookForm,
OrganizerSettingsForm, OrganizerUpdateForm, ReusableMediumCreateForm,
ReusableMediumUpdateForm, SSOClientForm, SSOProviderForm, TeamForm,
WebHookForm,
)
from pretix.control.forms.rrule import RRuleForm
from pretix.control.logdisplay import OVERVIEW_BANLIST
@@ -533,7 +534,7 @@ class OrganizerCreate(CreateView):
organizer=form.instance, name=_('Administrators'),
all_events=True, can_create_events=True, can_change_teams=True, can_manage_gift_cards=True,
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
can_manage_customers=True,
can_manage_customers=True, can_manage_reusable_media=True,
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
)
t.members.add(self.request.user)
@@ -2738,3 +2739,101 @@ class CustomerAnonymizeView(OrganizerDetailViewMixin, OrganizerPermissionRequire
'organizer': self.request.organizer.slug,
'customer': self.object.identifier,
})
class ReusableMediaListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
model = ReusableMedium
template_name = 'pretixcontrol/organizers/reusable_media.html'
permission = 'can_manage_reusable_media'
context_object_name = 'media'
def get_queryset(self):
qs = self.request.organizer.reusable_media.select_related(
'customer', 'linked_orderposition', 'linked_orderposition__order', 'linked_orderposition__order__event',
'linked_giftcard'
)
if self.filter_form.is_valid():
qs = self.filter_form.filter_qs(qs)
return qs
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['filter_form'] = self.filter_form
return ctx
@cached_property
def filter_form(self):
return ReusableMediaFilterForm(data=self.request.GET, request=self.request)
class ReusableMediumDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView):
template_name = 'pretixcontrol/organizers/reusable_medium.html'
permission = 'can_manage_reusable_media'
@cached_property
def medium(self):
return get_object_or_404(
self.request.organizer.reusable_media,
pk=self.kwargs.get('pk')
)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['medium'] = self.medium
return ctx
class ReusableMediumCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
template_name = 'pretixcontrol/organizers/reusable_medium_edit.html'
permission = 'can_manage_reusable_media'
context_object_name = 'medium'
form_class = ReusableMediumCreateForm
def get_form_kwargs(self):
ctx = super().get_form_kwargs()
c = ReusableMedium(organizer=self.request.organizer)
ctx['instance'] = c
return ctx
def form_valid(self, form):
r = super().form_valid(form)
form.instance.log_action('pretix.reusable_medium.created', user=self.request.user, data={
k: getattr(form.instance, k)
for k in form.changed_data
})
messages.success(self.request, _('Your changes have been saved.'))
return r
def get_success_url(self):
return reverse('control:organizer.reusable_medium', kwargs={
'organizer': self.request.organizer.slug,
'pk': self.object.pk,
})
class ReusableMediumUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
template_name = 'pretixcontrol/organizers/reusable_medium_edit.html'
permission = 'can_manage_reusable_media'
context_object_name = 'medium'
form_class = ReusableMediumUpdateForm
def get_object(self, queryset=None):
return get_object_or_404(
self.request.organizer.reusable_media,
pk=self.kwargs.get('pk')
)
def form_valid(self, form):
if form.has_changed():
self.object.log_action('pretix.reusable_medium.changed', user=self.request.user, data={
k: getattr(self.object, 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):
return reverse('control:organizer.reusable_medium', kwargs={
'organizer': self.request.organizer.slug,
'pk': self.object.pk,
})

View File

@@ -48,8 +48,8 @@ from django.utils.translation import gettext as _, pgettext
from pretix.base.models import (
EventMetaProperty, EventMetaValue, ItemMetaProperty, ItemMetaValue,
ItemVariation, ItemVariationMetaValue, Order, Organizer, SubEventMetaValue,
User, Voucher,
ItemVariation, ItemVariationMetaValue, Order, OrderPosition, Organizer,
SubEventMetaValue, User, Voucher,
)
from pretix.control.forms.event import EventWizardCopyForm
from pretix.control.permissions import (
@@ -172,6 +172,104 @@ def event_list(request):
return JsonResponse(doc)
@organizer_permission_required(("can_manage_gift_cards", "can_manage_reusable_media"))
def giftcard_select2(request, **kwargs):
query = request.GET.get('query', '')
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
if request.user.has_organizer_permission(request.organizer, 'can_manage_gift_cards', request):
qs = request.organizer.issued_gift_cards.filter(
Q(secret__icontains=query)
).order_by('secret')
else:
qs = request.organizer.issued_gift_cards.filter(
Q(secret__iexact=query)
).order_by('secret')
if not query:
qs = qs.none()
total = qs.count()
pagesize = 20
offset = (page - 1) * pagesize
doc = {
'results': [
{
'id': e.pk,
'text': str(e),
}
for e in qs[offset:offset + pagesize]
],
'pagination': {
"more": total >= (offset + pagesize)
}
}
return JsonResponse(doc)
@organizer_permission_required(("can_manage_reusable_media"))
def ticket_select2(request, **kwargs):
query = request.GET.get('query', '')
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
qs_orders = OrderPosition.all.select_related('order', 'order__event', 'item', 'variation').filter(
order__event__organizer=request.organizer,
).order_by()
exact_match = Q(secret__iexact=query)
soft_match = Q(secret__icontains=query)
qsplit = query.split("-")
if len(qsplit) >= 3 and qsplit[2].isdigit():
soft_match |= Q(order__event__slug__iexact=qsplit[0], order__code__iexact=qsplit[1], positionid=qsplit[2])
elif len(qsplit) >= 2 and qsplit[1].isdigit():
soft_match |= Q(order__code__istartswith=qsplit[0], positionid=qsplit[1])
elif len(qsplit) >= 2:
soft_match |= Q(order__event__slug__iexact=qsplit[0], order__code__istartswith=qsplit[1])
else:
soft_match |= Q(order__code__istartswith=qsplit[0])
if not request.user.has_active_staff_session(request.session.session_key):
qs_orders = qs_orders.filter(
exact_match | (
soft_match & (
Q(order__event__organizer_id__in=request.user.teams.filter(all_events=True, can_view_orders=True).values_list('organizer', flat=True))
| Q(order__event_id__in=request.user.teams.filter(can_view_orders=True).values_list('limit_events__id', flat=True))
)
)
)
else:
qs_orders = qs_orders.filter(exact_match | soft_match)
if not query:
qs_orders = qs_orders.none()
total = qs_orders.count()
pagesize = 20
offset = (page - 1) * pagesize
doc = {
'results': [
{
'id': op.pk,
'text': f'{op.order.code}-{op.positionid} ({str(op.item) + ((" - " + str(op.variation)) if op.variation else "")})',
'event': str(op.order.event)
}
for op in qs_orders[offset:offset + pagesize]
],
'pagination': {
"more": total >= (offset + pagesize)
}
}
return JsonResponse(doc)
@organizer_permission_required("can_manage_customers")
def customer_select2(request, **kwargs):
query = request.GET.get('query', '')