mirror of
https://github.com/pretix/pretix.git
synced 2026-08-08 10:27:49 +00:00
WIP
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from rest_framework import viewsets
|
||||
from django.db import transaction
|
||||
from .styles import PassLayout, AVAILABLE_STYLES_DICT, AVAILABLE_PLATFORMS
|
||||
from .styles import AVAILABLE_STYLES_DICT, AVAILABLE_PLATFORMS
|
||||
from .models import WalletLayout, WalletPlatformLayout
|
||||
from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
||||
from django.core.exceptions import ValidationError
|
||||
@@ -33,9 +33,8 @@ class WalletPlatformLayoutSerializer(I18nAwareModelSerializer):
|
||||
raise ValidationError(_("Invalid style"))
|
||||
style = platform_styles[data["style"]]
|
||||
|
||||
layout = PassLayout(style=style, layout=data["layout"])
|
||||
context = {"placeholders": get_editor_placeholders(self.context['event'])}
|
||||
layout.validate(context=context)
|
||||
style = style(event=self.context['event'], layout=data["layout"])
|
||||
style.validate()
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ from django.db import models
|
||||
from django.db.models import constraints, Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.models import LoggedModel
|
||||
from pretix.base.models import LoggedModel, OrderPosition
|
||||
from django_scopes import ScopedManager
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from pretix.plugins.wallet.styles import get_style
|
||||
from pretix.plugins.wallet.styles.base import PassLayout
|
||||
from pretix.plugins.wallet.styles.base import PassStyle
|
||||
|
||||
|
||||
class WalletLayout(LoggedModel):
|
||||
@@ -69,7 +69,10 @@ class WalletPlatformLayout(LoggedModel):
|
||||
@property
|
||||
def pass_layout(self):
|
||||
style = get_style(self.platform, self.style)
|
||||
return PassLayout(style=style, layout=self.layout)
|
||||
if style:
|
||||
return style(event=self.parent.event, layout=self.layout)
|
||||
else:
|
||||
raise RuntimeError(f"Style {self.platform}.{self.style} not found")
|
||||
|
||||
class WalletLayoutItem(models.Model):
|
||||
item = models.OneToOneField('pretixbase.Item', null=True, blank=True, related_name='walletlayout',
|
||||
@@ -79,3 +82,10 @@ class WalletLayoutItem(models.Model):
|
||||
def clean(self):
|
||||
if self.item.event != self.layout.event:
|
||||
raise ValidationError("cannot bind layout to item of different event")
|
||||
|
||||
# smth like this for apple, lets see what the best architecture for google will be
|
||||
# class AppleWalletPass(models.Model):
|
||||
# platform_layout = models.ForeignKey(WalletPlatformLayout, on_delete=models.PROTECT)
|
||||
# order_position = models.ForeignKey(OrderPosition, on_delete=models.PROTECT)
|
||||
# content = models.BinaryField()
|
||||
# updated_at = models.DateTimeField(null=True, auto_now=True)
|
||||
@@ -1,22 +1,21 @@
|
||||
from .apple import ApplePlatform, AppleWalletEventTicket
|
||||
from .google import GooglePlatform, GoogleWalletEventTicket
|
||||
from .base import PassLayout
|
||||
from .base import PassStyle
|
||||
|
||||
AVAILABLE_PLATFORMS = [ApplePlatform, GooglePlatform]
|
||||
|
||||
AVAILABLE_STYLES = {
|
||||
"apple": [AppleWalletEventTicket()],
|
||||
"google": [
|
||||
GoogleWalletEventTicket()
|
||||
],
|
||||
AVAILABLE_STYLES: dict[str, list[type[PassStyle]]] = {
|
||||
"apple": [AppleWalletEventTicket],
|
||||
"google": [GoogleWalletEventTicket],
|
||||
}
|
||||
|
||||
AVAILABLE_STYLES_DICT = {
|
||||
plat: {s.identifier: s for s in styls} for plat, styls in AVAILABLE_STYLES.items()
|
||||
}
|
||||
|
||||
def get_style(platform: str, identifier: str):
|
||||
|
||||
def get_style(platform: str, identifier: str) -> type[PassStyle] | None:
|
||||
return AVAILABLE_STYLES_DICT.get(platform, {}).get(identifier)
|
||||
|
||||
|
||||
__all__ = ["AVAILABLE_PLATFORMS", "AVAILABLE_STYLES", "PassLayout"]
|
||||
__all__ = ["AVAILABLE_PLATFORMS", "AVAILABLE_STYLES", "PassStyle"]
|
||||
|
||||
@@ -10,7 +10,6 @@ from .base import (
|
||||
WalletPlatform,
|
||||
PassStyle,
|
||||
PlaceholderFieldEntry,
|
||||
PassLayout,
|
||||
)
|
||||
from django.utils.translation import gettext as _
|
||||
from i18nfield.strings import LazyI18nString
|
||||
@@ -30,42 +29,6 @@ class ApplePlatform(WalletPlatform):
|
||||
identifier = "apple"
|
||||
name = _("Apple")
|
||||
|
||||
@classmethod
|
||||
def generate(cls, layout: PassLayout, op: OrderPosition):
|
||||
context = cls.get_context(op)
|
||||
|
||||
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.update({
|
||||
"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,
|
||||
})
|
||||
|
||||
data = layout.generate(context)
|
||||
return filename, "application/vnd.apple.pkpass", data
|
||||
|
||||
|
||||
class StringResource:
|
||||
# mapping string in default event locale -> LazyI18nString
|
||||
@@ -181,10 +144,39 @@ class AppleWalletStyle(PassStyle):
|
||||
}
|
||||
return pass_json
|
||||
|
||||
def generate(self, layout, context):
|
||||
for key in ["ca_certificate", "certificate", "key", "password", "locales"]:
|
||||
if key not in context:
|
||||
raise ValueError(f"{key} missing from context")
|
||||
def generate(self, op: OrderPosition):
|
||||
context = self.get_context(op)
|
||||
|
||||
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.update({
|
||||
"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,
|
||||
})
|
||||
|
||||
|
||||
|
||||
fields = self.get_pass_fields(layout, context)
|
||||
|
||||
@@ -214,7 +206,9 @@ class AppleWalletStyle(PassStyle):
|
||||
for lang, content in strings.generate().items():
|
||||
pkpass.add_file(f"{lang}.lproj/pass.strings", content)
|
||||
pkpass.add_file("pass.json", json.dumps(pass_json))
|
||||
return pkpass.finish()
|
||||
result = pkpass.finish()
|
||||
return filename, "application/vnd.apple.pkpass", result
|
||||
|
||||
|
||||
|
||||
class AppleWalletEventTicket(AppleWalletStyle):
|
||||
|
||||
@@ -9,23 +9,6 @@ class WalletPlatform:
|
||||
identifier: str
|
||||
name: str
|
||||
|
||||
@classmethod
|
||||
def generate(cls, layout: "PassLayout", op: OrderPosition) -> Any: # TODO: Typing
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_context(cls, op):
|
||||
from ..placeholders import get_wallet_placeholders, WalletPlaceholderContext
|
||||
|
||||
order = op.order
|
||||
event = order.event
|
||||
|
||||
return {
|
||||
"placeholders": get_wallet_placeholders(event),
|
||||
"placeholder_context": WalletPlaceholderContext(event=event, order=order, order_position=op),
|
||||
"locale": event.settings.locale, # TODO: should probably be order locale
|
||||
"locales": event.settings.locales,
|
||||
}
|
||||
|
||||
class FieldGroupType(enum.Enum):
|
||||
PLACEHOLDER = "placeholder"
|
||||
@@ -253,19 +236,21 @@ class PassStyle:
|
||||
fieldgroups: list[FieldGroup]
|
||||
preview_layout: list | None
|
||||
|
||||
def asdict(self):
|
||||
@classmethod
|
||||
def asdict(cls):
|
||||
return {
|
||||
"identifier": self.identifier,
|
||||
"name": self.name,
|
||||
"fieldgroups": [x.asdict() for x in self.fieldgroups],
|
||||
"preview_layout": self.preview_layout
|
||||
"identifier": cls.identifier,
|
||||
"name": cls.name,
|
||||
"fieldgroups": [x.asdict() for x in cls.fieldgroups],
|
||||
"preview_layout": cls.preview_layout
|
||||
}
|
||||
|
||||
def layout_schema(self, context):
|
||||
@classmethod
|
||||
def layout_schema(cls, context):
|
||||
schema = {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
# TODO: $id
|
||||
"title": self.name,
|
||||
"title": cls.name,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fieldgroups": {
|
||||
@@ -273,12 +258,12 @@ class PassStyle:
|
||||
"type": "object",
|
||||
"properties": {
|
||||
group.identifier: group.layout_schema(
|
||||
context=context, remaining_fields=self.fieldgroups[i:]
|
||||
context=context, remaining_fields=cls.fieldgroups[i:]
|
||||
)
|
||||
for (i, group) in enumerate(self.fieldgroups)
|
||||
for (i, group) in enumerate(cls.fieldgroups)
|
||||
},
|
||||
"required": [
|
||||
group.identifier for group in self.fieldgroups if group.required
|
||||
group.identifier for group in cls.fieldgroups if group.required
|
||||
],
|
||||
}
|
||||
},
|
||||
@@ -291,17 +276,15 @@ class PassStyle:
|
||||
}
|
||||
},
|
||||
}
|
||||
if any(group.required for group in self.fieldgroups):
|
||||
if any(group.required for group in cls.fieldgroups):
|
||||
schema["required"] = ["fieldgroups"]
|
||||
|
||||
return schema
|
||||
|
||||
def generate(self, layout, context):
|
||||
raise NotImplementedError()
|
||||
|
||||
def render_placeholder(self, context, content_type, content):
|
||||
@classmethod
|
||||
def render_placeholder(cls, context, content_type, content):
|
||||
placeholder = (
|
||||
context.get("placeholders")
|
||||
context.get("placeholders", {})
|
||||
.get(content_type, {})
|
||||
.get(content)
|
||||
)
|
||||
@@ -312,15 +295,31 @@ class PassStyle:
|
||||
|
||||
return None, None
|
||||
|
||||
def get_pass_fields(self, layout, context):
|
||||
|
||||
def __init__(self, event, layout):
|
||||
self.event = event
|
||||
self.layout = layout
|
||||
|
||||
def get_layout_context(self):
|
||||
return {"placeholders": {}}
|
||||
|
||||
def validate(self):
|
||||
schema = self.layout_schema(self.get_layout_context())
|
||||
try:
|
||||
jsonschema.validate(self.layout, schema)
|
||||
except jsonschema.ValidationError as e:
|
||||
raise ValidationError("Invalid layout: {}".format(str(e)))
|
||||
|
||||
def get_pass_fields(self, context):
|
||||
fields = {}
|
||||
for group in self.fieldgroups:
|
||||
if isinstance(group, PredefinedFieldGroup):
|
||||
pass
|
||||
|
||||
elif isinstance(group, PlaceholderFieldGroup):
|
||||
group_fields = fields.get(group.identifier, [])
|
||||
if group.identifier in layout["fieldgroups"]:
|
||||
for field in layout["fieldgroups"][group.identifier]["entries"]:
|
||||
if group.identifier in self.layout["fieldgroups"]:
|
||||
for field in self.layout["fieldgroups"][group.identifier]["entries"]:
|
||||
field_entry = {}
|
||||
if group.display == FieldGroupDisplay.WITH_LABEL:
|
||||
field_entry["label"] = LazyI18nString(field["label"])
|
||||
@@ -338,30 +337,13 @@ class PassStyle:
|
||||
f"Group {group.identifier} needs at least {group.min_entries} entries, but only {len(group_fields)} were provided"
|
||||
)
|
||||
fields[group.identifier] = group_fields[: group.max_entries]
|
||||
if (overflow_group := layout["fieldgroups"][group.identifier]['overflow']):
|
||||
if (overflow_group := self.layout["fieldgroups"][group.identifier]['overflow']):
|
||||
fields.setdefault(overflow_group, [])
|
||||
fields[overflow_group] += group_fields[group.max_entries:]
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown field group")
|
||||
return fields
|
||||
|
||||
|
||||
class PassLayout:
|
||||
style: PassStyle
|
||||
layout: dict
|
||||
|
||||
def __init__(self, style, layout):
|
||||
self.style = style
|
||||
self.layout = layout
|
||||
|
||||
def validate(self, context):
|
||||
schema = self.style.layout_schema(context)
|
||||
try:
|
||||
jsonschema.validate(self.layout, schema)
|
||||
except jsonschema.ValidationError as e:
|
||||
raise ValidationError("Invalid layout: {}".format(str(e)))
|
||||
|
||||
def generate(self, context):
|
||||
# TODO: how to handle nonexisting placeholders here?
|
||||
self.validate(context)
|
||||
return self.style.generate(self.layout, context)
|
||||
def generate(self, op: OrderPosition):
|
||||
raise NotImplementedError()
|
||||
@@ -3,7 +3,6 @@ from pretix.base.models import Event, OrderPosition
|
||||
from .base import (
|
||||
FieldGroupDisplay,
|
||||
ImageFieldGroup,
|
||||
PassLayout,
|
||||
PassStyle,
|
||||
PlaceholderFieldEntry,
|
||||
PredefinedFieldGroup,
|
||||
@@ -90,52 +89,28 @@ class GooglePlatform(WalletPlatform):
|
||||
identifier = "google"
|
||||
name = _("Google")
|
||||
|
||||
@classmethod
|
||||
def generate(cls, layout: PassLayout, op: OrderPosition):
|
||||
context = cls.get_context(op)
|
||||
|
||||
order = op.order
|
||||
event = order.event
|
||||
|
||||
context.update(
|
||||
{
|
||||
"credentials": event.settings.get("wallet_google_credentials").read(),
|
||||
"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):
|
||||
def _generate_class(self):
|
||||
output_class = EventTicketClass(
|
||||
context["issuerName"],
|
||||
context["classId"],
|
||||
self.event.organizer.name,
|
||||
get_class_id(self.event),
|
||||
MultipleDevicesAndHoldersAllowedStatus.multipleHolders, # TODO: Make configurable
|
||||
context["eventName"],
|
||||
self.event.name,
|
||||
ReviewStatus.underReview,
|
||||
context["locale"],
|
||||
self.event.settings.locale,
|
||||
)
|
||||
|
||||
output_class.homepage_uri(
|
||||
context["homepageUrl"],
|
||||
get_translated_string("Website", context["locale"]),
|
||||
get_translated_dict("Website", context["locales"]),
|
||||
eventreverse_absolute(self.event, "presale:event.index"),
|
||||
get_translated_string("Website", self.event.settings.locale),
|
||||
get_translated_dict("Website", self.event.settings.locales),
|
||||
)
|
||||
|
||||
if context.get("webhookUrl"): # TODO: enforce that it exists
|
||||
output_class.callback_url(context["webhookUrl"])
|
||||
# TODO: callback url
|
||||
# output_class.callback_url(eventreverse_absolute(event.organizer,"plugins:wallet:google_webhook",))
|
||||
|
||||
# TODO: move to pass settings or set defaults
|
||||
# if (event.settings.get('ticketoutput_googlepaypasses_latitude')
|
||||
@@ -200,53 +175,18 @@ class GoogleWalletStyle(PassStyle):
|
||||
# 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"]
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = EventTicketObject(
|
||||
object_id, class_id, ObjectState.active, context["locale"]
|
||||
get_object_id(op), class_id, ObjectState.active, self.event.settings.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)
|
||||
def generate(self, op):
|
||||
self.op = op
|
||||
comms = Comms(self.event.settings.get("wallet_google_credentials").read())
|
||||
|
||||
class_object = self._generate_class(layout, context, fields)
|
||||
ticket_object = self._generate_object(layout, context, fields)
|
||||
class_object = self._generate_class()
|
||||
ticket_object = self._generate_object(op, class_id=class_object['id'])
|
||||
|
||||
# TODO: privacy screen
|
||||
class_object = comms.put_item(ClassType.eventTicketClass, class_object['id'], class_object)
|
||||
@@ -327,8 +267,8 @@ class GoogleWalletEventTicket(GoogleWalletStyle):
|
||||
]
|
||||
]
|
||||
|
||||
def _generate_object(self, layout: PassLayout, context, fields):
|
||||
output_object = super()._generate_object(layout, context, fields)
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = super()._generate_object(op, class_id)
|
||||
|
||||
if fields["code"]:
|
||||
output_object.barcode(
|
||||
|
||||
@@ -23,7 +23,6 @@ from .styles import (
|
||||
AVAILABLE_STYLES,
|
||||
AVAILABLE_PLATFORMS,
|
||||
AVAILABLE_STYLES_DICT,
|
||||
PassLayout,
|
||||
)
|
||||
from django.contrib import messages
|
||||
from django.contrib.staticfiles import finders
|
||||
@@ -172,9 +171,8 @@ class LayoutPreviewView(EventPermissionRequiredMixin, View):
|
||||
language(request.event.settings.locale, request.event.settings.region),
|
||||
):
|
||||
p = get_preview_position(request.event)
|
||||
layout = PassLayout(style=style, layout=layout)
|
||||
context = {"placeholders": get_wallet_placeholders(event)}
|
||||
layout.validate(context=context)
|
||||
layout = style(event=event, layout=layout)
|
||||
layout.validate()
|
||||
|
||||
fname, mimet, data = platform.generate(layout, p)
|
||||
resp = HttpResponse(data, content_type=mimet)
|
||||
|
||||
@@ -4,9 +4,9 @@ from pretix.plugins.wallet.styles.base import (
|
||||
WalletPlatform,
|
||||
PlaceholderFieldGroup,
|
||||
FieldContentType,
|
||||
PassLayout,
|
||||
FieldGroupType,
|
||||
FieldEntryType,
|
||||
FieldGroupDisplay
|
||||
)
|
||||
from django.utils.translation import gettext as _
|
||||
import jsonschema
|
||||
@@ -49,50 +49,20 @@ class TicketTestStyle(PassStyle):
|
||||
name=_("Text 2"),
|
||||
content_type=FieldContentType.TEXT,
|
||||
required=False,
|
||||
labels=False,
|
||||
display=FieldGroupDisplay.PLAIN,
|
||||
),
|
||||
PlaceholderFieldGroup(
|
||||
identifier="image1",
|
||||
name=_("Image 1"),
|
||||
content_type=FieldContentType.IMAGE,
|
||||
required=False,
|
||||
labels=False,
|
||||
display=FieldGroupDisplay.PLAIN,
|
||||
),
|
||||
]
|
||||
|
||||
def generate(self, layout, context):
|
||||
output = f"Generated Pass: {self.name}\n\n"
|
||||
for group in self.fieldgroups:
|
||||
if group.identifier in layout["fieldgroups"]:
|
||||
output += f"Group: {group.name}\n"
|
||||
if isinstance(group, PredefinedFieldGroup):
|
||||
output += "PREDEFINED\n"
|
||||
elif isinstance(group, PlaceholderFieldGroup):
|
||||
for field in layout["fieldgroups"][group.identifier]["entries"]:
|
||||
if group.labels:
|
||||
label = LazyI18nString(field["label"])
|
||||
output += f"{label}: "
|
||||
if field["type"] == FieldEntryType.PLACEHOLDER.value:
|
||||
placeholder = (
|
||||
context.get("placeholders")
|
||||
.get(group.content_type.value, {})
|
||||
.get(field["content"])
|
||||
)
|
||||
if placeholder:
|
||||
output += placeholder["evaluate"](
|
||||
*context.get("evaluation_context", [])
|
||||
)
|
||||
else:
|
||||
output += f"UNKNOWN: {field['content']}"
|
||||
elif field["type"] == FieldEntryType.TEXT.value:
|
||||
output += str(LazyI18nString(field["content"]))
|
||||
elif field["type"] == FieldEntryType.IMAGE.value:
|
||||
output += f"<IMG>{field['content']}</IMG>"
|
||||
output += "\n"
|
||||
else:
|
||||
raise ValueError("Unknown field group")
|
||||
output += "\n"
|
||||
return output
|
||||
def generate(self, op):
|
||||
fields = self.get_pass_fields({})
|
||||
return fields
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -105,7 +75,7 @@ def layout_context():
|
||||
|
||||
|
||||
def test_schema_generation_minimal():
|
||||
style = MinimalTestStyle()
|
||||
style = MinimalTestStyle
|
||||
context = {}
|
||||
schema = style.layout_schema(context)
|
||||
assert isinstance(schema, dict)
|
||||
@@ -117,7 +87,7 @@ def test_schema_generation_minimal():
|
||||
|
||||
|
||||
def test_schema_ticket_generation(layout_context):
|
||||
style = TicketTestStyle()
|
||||
style = TicketTestStyle
|
||||
schema = style.layout_schema(layout_context)
|
||||
assert isinstance(schema, dict)
|
||||
assert "properties" in schema
|
||||
@@ -194,7 +164,7 @@ def test_schema_ticket_generation(layout_context):
|
||||
],
|
||||
)
|
||||
def test_schema_ticket_valid(layout_context, layout):
|
||||
style = TicketTestStyle()
|
||||
style = TicketTestStyle
|
||||
schema = style.layout_schema(layout_context)
|
||||
|
||||
jsonschema.validate(layout, schema)
|
||||
@@ -287,7 +257,7 @@ def test_schema_ticket_valid(layout_context, layout):
|
||||
],
|
||||
)
|
||||
def test_schema_ticket_invalid(layout_context, layout):
|
||||
style = TicketTestStyle()
|
||||
style = TicketTestStyle
|
||||
schema = style.layout_schema(layout_context)
|
||||
|
||||
with pytest.raises(jsonschema.ValidationError):
|
||||
@@ -295,7 +265,7 @@ def test_schema_ticket_invalid(layout_context, layout):
|
||||
|
||||
|
||||
def test_style_representation():
|
||||
style = TicketTestStyle()
|
||||
style = TicketTestStyle
|
||||
style_dict = style.asdict()
|
||||
assert style_dict["platform"] == "test_platform"
|
||||
assert style_dict["identifier"] == "test_ticket"
|
||||
@@ -309,7 +279,7 @@ def test_style_representation():
|
||||
|
||||
|
||||
def test_layout_generate(layout_context):
|
||||
style = TicketTestStyle()
|
||||
style = TicketTestStyle
|
||||
layout = {
|
||||
"fieldgroups": {
|
||||
"text1": {
|
||||
@@ -325,8 +295,8 @@ def test_layout_generate(layout_context):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass_layout = PassLayout(style, layout)
|
||||
# TODO: create event and pass here
|
||||
pass_layout = style(event=None, layout=layout)
|
||||
generated_pass = pass_layout.generate(layout_context)
|
||||
|
||||
assert (
|
||||
|
||||
Reference in New Issue
Block a user