mirror of
https://github.com/pretix/pretix.git
synced 2026-08-11 10:57:00 +00:00
399 lines
14 KiB
Python
399 lines
14 KiB
Python
from pretix.base.models import Event, OrderPosition
|
||
|
||
from .base import (
|
||
FieldGroupDisplay,
|
||
ImageFieldGroup,
|
||
PassLayout,
|
||
PassStyle,
|
||
PlaceholderFieldEntry,
|
||
PredefinedFieldGroup,
|
||
TextFieldGroup,
|
||
WalletPlatform,
|
||
)
|
||
from django.utils.translation import gettext_lazy as _, gettext
|
||
import json
|
||
|
||
from walletobjects import ButtonJWT, EventTicketClass, EventTicketObject
|
||
from walletobjects.comms import Comms
|
||
from walletobjects.constants import (
|
||
Barcode,
|
||
ClassType,
|
||
ConfirmationCode,
|
||
DoorsOpen,
|
||
MultipleDevicesAndHoldersAllowedStatus,
|
||
ObjectState,
|
||
ObjectType,
|
||
ReviewStatus,
|
||
Seat,
|
||
)
|
||
from pretix.base.settings import GlobalSettingsObject
|
||
import uuid
|
||
from pretix.multidomain.urlreverse import eventreverse_absolute
|
||
from django.utils import translation
|
||
from django.conf import settings
|
||
|
||
|
||
def _get_instance_uuid():
|
||
gs = GlobalSettingsObject()
|
||
if not gs.settings.wallet_google_instance_uuid:
|
||
gs.settings.wallet_google_instance_uuid = str(uuid.uuid4())
|
||
|
||
return gs.settings.wallet_google_instance_uuid
|
||
|
||
|
||
def get_class_id(event: Event):
|
||
# TODO: add layout id somewhere
|
||
instance_uuid = _get_instance_uuid()
|
||
issuer_id = event.settings.get("wallet_google_issuer_id")
|
||
return "%s.pretix-%s-%s-%s" % (
|
||
issuer_id,
|
||
instance_uuid,
|
||
event.organizer.slug,
|
||
event.slug,
|
||
)
|
||
|
||
|
||
def get_object_id(op: OrderPosition):
|
||
instance_uuid = _get_instance_uuid()
|
||
issuer_id = op.order.event.settings.get("wallet_google_issuer_id")
|
||
|
||
return "%s.pretix-%s-%s-%s-%s-%s-1" % (
|
||
issuer_id,
|
||
instance_uuid,
|
||
op.order.event.organizer.slug,
|
||
op.order.event.slug,
|
||
op.order.code,
|
||
op.positionid,
|
||
)
|
||
|
||
|
||
def get_translated_dict(string, locales):
|
||
translated = {}
|
||
|
||
for locale in locales:
|
||
translation.activate(locale)
|
||
translated[locale] = gettext(string)
|
||
translation.deactivate()
|
||
|
||
return translated
|
||
|
||
|
||
def get_translated_string(string, locale):
|
||
translation.activate(locale)
|
||
translated = gettext(string)
|
||
translation.deactivate()
|
||
|
||
return translated
|
||
|
||
|
||
class GooglePlatform(WalletPlatform):
|
||
identifier = "google"
|
||
name = _("Google")
|
||
|
||
@classmethod
|
||
def generate(cls, layout: PassLayout, op: OrderPosition):
|
||
from ..views import get_layout_variables
|
||
|
||
order = op.order
|
||
event = order.event
|
||
|
||
context = {
|
||
"placeholders": get_layout_variables(event), # TODO: move to higher class
|
||
"evaluation_context": [op, order, event],
|
||
"credentials": event.settings.get("wallet_google_credentials").read(),
|
||
"locale": event.settings.locale,
|
||
"locales": event.settings.locales,
|
||
"issuerName": event.organizer.name,
|
||
"eventName": event.name,
|
||
# TODO: use other classId and objectId in preview mode
|
||
"classId": get_class_id(event),
|
||
"objectId": get_object_id(op),
|
||
"homepageUrl": eventreverse_absolute(event, "presale:event.index"),
|
||
# TODO: add webhook view & register in pass
|
||
"webhookUrl": "", # eventreverse_absolute(event.organizer,"plugins:wallet:google_webhook",))
|
||
}
|
||
|
||
data = layout.generate(context)
|
||
return "url", "text/plain", data
|
||
|
||
|
||
class GoogleWalletStyle(PassStyle):
|
||
platform = GooglePlatform
|
||
|
||
def _generate_class(self, layout: PassLayout, context, fields):
|
||
output_class = EventTicketClass(
|
||
context["issuerName"],
|
||
context["classId"],
|
||
MultipleDevicesAndHoldersAllowedStatus.multipleHolders, # TODO: Make configurable
|
||
context["eventName"],
|
||
ReviewStatus.underReview,
|
||
context["locale"],
|
||
)
|
||
|
||
output_class.homepage_uri(
|
||
context["homepageUrl"],
|
||
get_translated_string("Website", context["locale"]),
|
||
get_translated_dict("Website", context["locales"]),
|
||
)
|
||
# TODO: add webhook view & register in pass
|
||
# output_class.callback_url(context['webhookUrl'])
|
||
|
||
# TODO: move to pass settings or set defaults
|
||
# if (event.settings.get('ticketoutput_googlepaypasses_latitude')
|
||
# and event.settings.get('ticketoutput_googlepaypasses_longitude')):
|
||
# output_class.locations(
|
||
# event.settings.get('ticketoutput_googlepaypasses_latitude'),
|
||
# event.settings.get('ticketoutput_googlepaypasses_longitude')
|
||
# )
|
||
# elif event.geo_lat and event.geo_lon:
|
||
# output_class.locations(
|
||
# event.geo_lat,
|
||
# event.geo_lon
|
||
# )
|
||
|
||
# output_class.country_code(event.settings.locale)
|
||
|
||
# if event.settings.get('ticketoutput_googlepaypasses_hero'):
|
||
# output_class.hero_image(
|
||
# urljoin(django_settings.SITE_URL, event.settings.get('ticketoutput_googlepaypasses_hero').url),
|
||
# str(event.name),
|
||
# event.name,
|
||
# )
|
||
|
||
# output_class.hex_background_color(event.settings.get('primary_color'))
|
||
# output_class.event_id('pretix-%s-%s-%s' % (gs.settings.get('update_check_id'), event.organizer.id, event.id))
|
||
|
||
# if event.settings.get('ticketoutput_googlepaypasses_logo'):
|
||
# output_class.logo(
|
||
# urljoin(django_settings.SITE_URL, event.settings.get('ticketoutput_googlepaypasses_logo').url),
|
||
# str(event.name),
|
||
# event.name,
|
||
# )
|
||
|
||
# if event.location:
|
||
# name = {}
|
||
# address = {}
|
||
|
||
# for key, value in event.location.data.items():
|
||
# lines = value.splitlines()
|
||
# name[key] = lines[0]
|
||
# # We must provide at least one address line each for the name and address - no way around it.
|
||
# if len(lines) > 1:
|
||
# address[key] = '\n'.join(value.splitlines()[1:])
|
||
# else:
|
||
# address[key] = lines[0]
|
||
|
||
# output_class.venue(name, address)
|
||
|
||
# if event.date_from and event.date_to and event.date_admission:
|
||
# output_class.date_time(
|
||
# DoorsOpen.doorsOpen,
|
||
# event.date_admission.isoformat(),
|
||
# event.date_from.isoformat(),
|
||
# event.date_to.isoformat(),
|
||
# )
|
||
|
||
# output_class.confirmation_code_label(ConfirmationCode.orderNumber)
|
||
|
||
# if event.seating_plan_id is not None:
|
||
# output_class.seat_label(Seat.seat)
|
||
|
||
# return self._comms().put_item(ClassType.eventTicketClass, class_name, output_class)
|
||
return output_class
|
||
|
||
def _generate_object(self, layout: PassLayout, context, fields):
|
||
class_id = context["classId"]
|
||
object_id = context["objectId"]
|
||
output_object = EventTicketObject(
|
||
object_id, class_id, ObjectState.active, context["locale"]
|
||
)
|
||
|
||
# output_object.barcode(Barcode.qrCode, op.secret, op.secret)
|
||
|
||
# output_object.reservation_info("%s-%s" % (op.order.event.slug, op.order.code))
|
||
# output_object.ticket_holder_name(op.attendee_name or (op.addon_to.attendee_name if op.addon_to else ''))
|
||
# output_object.ticket_number(op.secret)
|
||
# output_object.ticket_type(
|
||
# get_translated_dict(
|
||
# str(op.item) + (" – " + str(op.variation.value) if op.variation else ""),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
|
||
# places = django_settings.CURRENCY_PLACES.get(op.order.event.currency, 2)
|
||
# output_object.face_value(int(op.price * 1000 ** places), op.order.event.currency)
|
||
|
||
# if op.order.event.seating_plan_id is not None:
|
||
# if op.seat:
|
||
# output_object.seat(
|
||
# get_translated_dict(
|
||
# _(str(op.seat)),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
# else:
|
||
# output_object.seat(
|
||
# get_translated_dict(
|
||
# _('General admission'),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
|
||
# return self._comms().put_item(ObjectType.eventTicketObject, object_name, output_object)
|
||
return output_object
|
||
|
||
def generate(self, layout, context):
|
||
comms = Comms(context["credentials"])
|
||
fields = self.get_pass_fields(layout, context)
|
||
|
||
class_object = self._generate_class(layout, context, fields)
|
||
ticket_object = self._generate_object(layout, context, fields)
|
||
|
||
generated_jwt = comms.sign_jwt(
|
||
ButtonJWT(
|
||
origins=[settings.SITE_URL],
|
||
issuer=comms.client_email,
|
||
event_ticket_classes=[class_object],
|
||
event_ticket_objects=[ticket_object],
|
||
skinny=False,
|
||
)
|
||
)
|
||
|
||
return "https://pay.google.com/gp/v/save/%s" % generated_jwt
|
||
|
||
# from ..views import get_layout_variables
|
||
|
||
# order = op.order
|
||
# event = order.event
|
||
# filename = "{}-{}.pkpass".format(order.event.slug, order.code)
|
||
|
||
# ticket = str(op.item.name)
|
||
# if op.variation:
|
||
# ticket += " - " + str(op.variation)
|
||
|
||
# serialNumber = "%s-%s-%s-%d" % (
|
||
# order.event.organizer.slug,
|
||
# order.event.slug,
|
||
# order.code,
|
||
# op.pk,
|
||
# )
|
||
|
||
# context = {
|
||
# "placeholders": get_layout_variables(op.order.event),
|
||
# "evaluation_context": [op, order, order.event],
|
||
# "ca_certificate": order.event.settings.wallet_apple_ca_certificate.read(),
|
||
# "certificate": order.event.settings.wallet_apple_certificate.read(),
|
||
# "key": order.event.settings.wallet_apple_key.read(),
|
||
# "password": order.event.settings.wallet_apple_key_password,
|
||
# "description": _("Ticket for {event} ({product})").format( # TODO: i18n
|
||
# event=event.name, product=ticket
|
||
# ),
|
||
# "organizationName": event.organizer.name,
|
||
# "passTypeIdentifier": order.event.settings.wallet_apple_pass_type_id,
|
||
# "teamIdentifier": order.event.settings.wallet_apple_team_id,
|
||
# "serialNumber": serialNumber,
|
||
# "locales": event.settings.locales,
|
||
# }
|
||
|
||
# data = layout.generate(context)
|
||
# return filename, "application/vnd.apple.pkpass", data
|
||
|
||
|
||
class GoogleWalletEventTicket(GoogleWalletStyle):
|
||
identifier = "event"
|
||
name = "Event Ticket"
|
||
fieldgroups = [
|
||
ImageFieldGroup(
|
||
identifier="logo",
|
||
name=_("Logo"),
|
||
min_entries=0,
|
||
max_entries=1,
|
||
default_entries=[
|
||
PlaceholderFieldEntry(
|
||
content="poweredby",
|
||
)
|
||
],
|
||
),
|
||
PredefinedFieldGroup(identifier="seating", name=_("Seating")),
|
||
TextFieldGroup(
|
||
identifier="code",
|
||
name=_("QR-Code"),
|
||
max_entries=1,
|
||
display=FieldGroupDisplay.CODE,
|
||
default_entries=[
|
||
PlaceholderFieldEntry(
|
||
content="secret",
|
||
)
|
||
],
|
||
),
|
||
]
|
||
preview_layout = [
|
||
[
|
||
{
|
||
"children": [
|
||
{"fieldgroup": "logo", "relSize": 1},
|
||
{
|
||
"value": "issuerName",
|
||
"relSize": 3,
|
||
"display": ["large", "centered"],
|
||
},
|
||
]
|
||
},
|
||
{
|
||
"children": [
|
||
{"value": "venueName", "display": "small"},
|
||
{"value": "eventName", "display": "large"},
|
||
],
|
||
"direction": "column",
|
||
},
|
||
{
|
||
"children": [
|
||
{"value": "01/01/1970", "label": "Date"},
|
||
{"value": "12:34", "label": "Time"},
|
||
]
|
||
},
|
||
{"fieldgroup": "seating"},
|
||
{"fieldgroup": "code"},
|
||
]
|
||
]
|
||
|
||
|
||
def _generate_object(self, layout: PassLayout, context, fields):
|
||
output_object = super()._generate_object(layout, context, fields)
|
||
|
||
if fields["code"]:
|
||
output_object.barcode(Barcode.qrCode, fields["code"][0]["value"], fields["code"][0]["value"])
|
||
|
||
# output_object.reservation_info("%s-%s" % (op.order.event.slug, op.order.code))
|
||
# output_object.ticket_holder_name(op.attendee_name or (op.addon_to.attendee_name if op.addon_to else ''))
|
||
output_object.ticket_holder_name("Some name")
|
||
output_object.ticket_number(fields["code"][0]["value"])
|
||
# output_object.ticket_type(
|
||
# get_translated_dict(
|
||
# str(op.item) + (" – " + str(op.variation.value) if op.variation else ""),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
|
||
# places = django_settings.CURRENCY_PLACES.get(op.order.event.currency, 2)
|
||
# output_object.face_value(int(op.price * 1000 ** places), op.order.event.currency)
|
||
|
||
# if op.order.event.seating_plan_id is not None:
|
||
# if op.seat:
|
||
# output_object.seat(
|
||
# get_translated_dict(
|
||
# _(str(op.seat)),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
# else:
|
||
# output_object.seat(
|
||
# get_translated_dict(
|
||
# _('General admission'),
|
||
# op.order.event.settings.get('locales')
|
||
# )
|
||
# )
|
||
|
||
# return self._comms().put_item(ObjectType.eventTicketObject, object_name, output_object)
|
||
return output_object
|