mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
237 lines
9.6 KiB
Python
237 lines
9.6 KiB
Python
#
|
|
# This file is part of pretix (Community Edition).
|
|
#
|
|
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
|
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
|
# Public License as published by the Free Software Foundation in version 3 of the License.
|
|
#
|
|
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
|
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
|
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
|
# this file, see <https://pretix.eu/about/en/license>.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
|
# <https://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
|
|
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
|
|
#
|
|
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
|
|
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
|
|
#
|
|
# This file contains Apache-licensed contributions copyrighted by: Ian Williams, Tobias Kunze
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under the License.
|
|
|
|
import os
|
|
import tempfile
|
|
from collections import OrderedDict
|
|
from typing import Tuple
|
|
from zipfile import ZipFile
|
|
|
|
from django import forms
|
|
from django.http import HttpRequest
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from pretix.base.models import Event, Order, OrderPosition
|
|
from pretix.base.settings import SettingsSandbox
|
|
|
|
|
|
class BaseTicketOutput:
|
|
"""
|
|
This is the base class for all ticket outputs.
|
|
"""
|
|
|
|
def __init__(self, event: Event):
|
|
self.event = event
|
|
self.settings = SettingsSandbox('ticketoutput', self.identifier, event)
|
|
|
|
def __str__(self):
|
|
return self.identifier
|
|
|
|
@property
|
|
def is_enabled(self) -> bool:
|
|
"""
|
|
Returns whether or whether not this output is enabled.
|
|
By default, this is determined by the value of the ``_enabled`` setting.
|
|
"""
|
|
return self.settings.get('_enabled', as_type=bool)
|
|
|
|
@property
|
|
def multi_download_enabled(self) -> bool:
|
|
"""
|
|
Returns whether or not the ``generate_order`` method may be called. Returns
|
|
``True`` by default.
|
|
"""
|
|
return True
|
|
|
|
def generate(self, position: OrderPosition) -> Tuple[str, str, str]:
|
|
"""
|
|
This method should generate the download file and return a tuple consisting of a
|
|
filename, a file type and file content. The extension will be taken from the filename
|
|
which is otherwise ignored.
|
|
|
|
Alternatively, you can pass a tuple consisting of an arbitrary string, ``text/uri-list``
|
|
and a single URL. In this case, the user will be redirected to this link instead of
|
|
being asked to download a generated file.
|
|
|
|
.. note:: If the event uses the event series feature (internally called subevents)
|
|
and your generated ticket contains information like the event name or date,
|
|
you probably want to display the properties of the subevent. A common pattern
|
|
to do this would be a declaration ``ev = position.subevent or position.order.event``
|
|
and then access properties that are present on both classes like ``ev.name`` or
|
|
``ev.date_from``.
|
|
|
|
.. note:: Should you elect to use the URI redirection feature instead of offering downloads,
|
|
you should also set the ``multi_download_enabled``-property to ``False``.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def generate_order(self, order: Order) -> Tuple[str, str, str]:
|
|
"""
|
|
This method is the same as order() but should not generate one file per order position
|
|
but instead one file for the full order.
|
|
|
|
This method is optional to implement. If you don't implement it, the default
|
|
implementation will offer a zip file of the generate() results for the order positions.
|
|
|
|
This method should generate a download file and return a tuple consisting of a
|
|
filename, a file type and file content. The extension will be taken from the filename
|
|
which is otherwise ignored.
|
|
|
|
If you override this method, make sure that positions that are addons (i.e. ``addon_to``
|
|
is set) are only outputted if the event setting ``ticket_download_addons`` is active.
|
|
Do the same for positions that are non-admission without ``ticket_download_nonadm`` active.
|
|
If you want, you can just iterate over ``order.positions_with_tickets`` which applies the
|
|
appropriate filters for you.
|
|
"""
|
|
with tempfile.TemporaryDirectory() as d:
|
|
with ZipFile(os.path.join(d, 'tmp.zip'), 'w') as zipf:
|
|
for pos in order.positions_with_tickets:
|
|
fname, __, content = self.generate(pos)
|
|
zipf.writestr('{}-{}{}'.format(
|
|
order.code, pos.positionid, os.path.splitext(fname)[1]
|
|
), content)
|
|
|
|
with open(os.path.join(d, 'tmp.zip'), 'rb') as zipf:
|
|
return '{}-{}.zip'.format(order.code, self.identifier), 'application/zip', zipf.read()
|
|
|
|
@property
|
|
def verbose_name(self) -> str:
|
|
"""
|
|
A human-readable name for this ticket output. This should be short but
|
|
self-explanatory. Good examples include 'PDF tickets' and 'Passbook'.
|
|
"""
|
|
raise NotImplementedError() # NOQA
|
|
|
|
@property
|
|
def identifier(self) -> str:
|
|
"""
|
|
A short and unique identifier for this ticket output.
|
|
This should only contain lowercase letters and in most
|
|
cases will be the same as your package name.
|
|
"""
|
|
raise NotImplementedError() # NOQA
|
|
|
|
@property
|
|
def settings_form_fields(self) -> dict:
|
|
"""
|
|
When the event's administrator visits the event configuration
|
|
page, this method is called to return the configuration fields available.
|
|
|
|
It should therefore return a dictionary where the keys should be (unprefixed)
|
|
settings keys and the values should be corresponding Django form fields.
|
|
|
|
The default implementation returns the appropriate fields for the ``_enabled``
|
|
setting mentioned above.
|
|
|
|
We suggest that you return an ``OrderedDict`` object instead of a dictionary
|
|
and make use of the default implementation. Your implementation could look
|
|
like this::
|
|
|
|
@property
|
|
def settings_form_fields(self):
|
|
return OrderedDict(
|
|
list(super().settings_form_fields.items()) + [
|
|
('paper_size',
|
|
forms.CharField(
|
|
label=_('Paper size'),
|
|
required=False
|
|
))
|
|
]
|
|
)
|
|
|
|
.. WARNING:: It is highly discouraged to alter the ``_enabled`` field of the default
|
|
implementation.
|
|
"""
|
|
return OrderedDict([
|
|
('_enabled',
|
|
forms.BooleanField(
|
|
label=_('Enable ticket format'),
|
|
required=False,
|
|
)),
|
|
])
|
|
|
|
def settings_content_render(self, request: HttpRequest) -> str:
|
|
"""
|
|
When the event's administrator visits the event configuration
|
|
page, this method is called. It may return HTML containing additional information
|
|
that is displayed below the form fields configured in ``settings_form_fields``.
|
|
"""
|
|
pass
|
|
|
|
@property
|
|
def download_button_text(self) -> str:
|
|
"""
|
|
The text on the download button in the frontend.
|
|
"""
|
|
return _('Download ticket')
|
|
|
|
@property
|
|
def long_download_button_text(self) -> str:
|
|
"""
|
|
The text on the large download button in the frontend.
|
|
"""
|
|
return self.download_button_text
|
|
|
|
@property
|
|
def multi_download_button_text(self) -> str:
|
|
"""
|
|
The text on the multi download button in the frontend.
|
|
"""
|
|
return self.download_button_text
|
|
|
|
@property
|
|
def download_button_icon(self) -> str:
|
|
"""
|
|
The Font Awesome icon on the download button in the frontend.
|
|
"""
|
|
return 'fa-download'
|
|
|
|
@property
|
|
def preview_allowed(self) -> bool:
|
|
"""
|
|
By default, the ``generate()`` method is called for generating a preview in the pretix backend.
|
|
In case your plugin cannot generate previews for any reason, you can manually disable it here.
|
|
"""
|
|
return True
|
|
|
|
@property
|
|
def javascript_required(self) -> bool:
|
|
"""
|
|
If this property is set to true, the download-button for this ticket-type will not be displayed
|
|
when the user's browser has JavaScript disabled.
|
|
|
|
Defaults to ``False``
|
|
"""
|
|
return False
|