import hashlib from django import forms from django.dispatch import receiver from django.template.loader import get_template from django.urls import resolve, reverse from django.utils.translation import gettext_lazy as _ from pretix.base.models import Order, OrderPosition, QuestionAnswer from pretix.base.settings import settings_hierarkey from pretix.base.signals import event_copy_data from pretix.control.signals import nav_event_settings from pretix.presale.signals import ( front_page_bottom, html_head, process_response, question_form_fields, ) from urllib.parse import urlencode settings_hierarkey.add_default("public_registrations_items", [], list) settings_hierarkey.add_default("public_registrations_questions", [], list) settings_hierarkey.add_default("public_registrations_show_attendee_name", False, bool) settings_hierarkey.add_default("public_registrations_show_item_name", False, bool) @receiver(html_head, dispatch_uid="public_registrations_html_head") def add_public_registrations_html_head(sender, request=None, **kwargs): url = resolve(request.path_info) if "event.index" not in url.url_name: return "" return sender.cache.get_or_set( "public_registrations_html_head", get_template("pretix_public_registrations/head.html").render(), ) @receiver(question_form_fields, dispatch_uid="public_registration_question") def add_public_registration_question(sender, position, **kwargs): if str(position.item.pk) not in sender.settings.get("public_registrations_items"): return {} public_questions = sender.questions.filter( pk__in=sender.settings.get("public_registrations_questions") ) headers = ( ( [_("Product")] if sender.settings.get("public_registrations_show_item_name") else [] ) + ( [_("Name")] if sender.settings.get("public_registrations_show_attendee_name") else [] ) + [q.question for q in public_questions] ) return { "public_registrations_public_registration": forms.BooleanField( label=_("Public registration"), required=False, help_text=_( "A gravatar image based on a hash of your e-mail address as well as the answers to " "the following questions will be publicly shown: %(qlist)s" ) % {"qlist": ", ".join(str(h) for h in headers)}, ) } @receiver(signal=front_page_bottom, dispatch_uid="public_registrations_table") def add_public_registrations_table(sender, **kwargs): def get_gravatar_url(email, size=40): email_encoded = email.lower().encode("utf-8") email_hash = hashlib.sha256(email_encoded).hexdigest() params = urlencode({"d": "wavatar", "s": str(size), "r": "g"}) return f"https://gravatar.com/avatar/{email_hash}?{params}" if not sender.settings.get("public_registrations_items") and not ( sender.settings.get("public_registrations_questions") and sender.settings.get("public_registrations_show_item_name") and sender.settings.get("public_registrations_show_attendee_name") ): return "" public_questions = sender.questions.filter( pk__in=sender.settings.get("public_registrations_questions") ) headers = ( ( [_("Product")] if sender.settings.get("public_registrations_show_item_name") else [] ) + ( [_("Name")] if sender.settings.get("public_registrations_show_attendee_name") else [] ) + [q.question for q in public_questions] ) order_positions = ( OrderPosition.objects.filter( order__event=sender, item__pk__in=sender.settings.get("public_registrations_items"), order__testmode=(sender.testmode), ) .exclude(order__status=Order.STATUS_CANCELED) .order_by("order__datetime") ) public_order_positions = [ op for op in order_positions if op.meta_info_data.get("question_form_data", {}).get( "public_registrations_public_registration" ) ] answers = QuestionAnswer.objects.filter( orderposition__in=public_order_positions, question__in=public_questions ) public_answers = {(a.orderposition_id, a.question_id): a for a in answers} public_registrations = [ { "gr_url": get_gravatar_url(pop.attendee_email or pop.order.code, size=24), "fields": ( [pop.item.name] if sender.settings.get("public_registrations_show_item_name") else [] ) + ( [pop.attendee_name_cached] if sender.settings.get("public_registrations_show_attendee_name") else [] ) + [ ( public_answers[(pop.pk, pq.pk)].answer if public_answers.get((pop.pk, pq.pk)) else "" ) for pq in public_questions ], } for pop in public_order_positions ] template = get_template("pretix_public_registrations/front_page.html") return template.render( {"headers": headers, "public_registrations": public_registrations} ) @receiver(signal=process_response, dispatch_uid="public_registragions_csp_headers") def add_public_registrations_csp_headers(sender, request=None, response=None, **kwargs): if "event.index" in resolve(request.path_info).url_name: response["Content-Security-Policy"] = "img-src https://gravatar.com" return response @receiver(signal=nav_event_settings, dispatch_uid="public_registrations_nav_settings") def navbar_settings(sender, request, **kwargs): url = resolve(request.path_info) return [ { "label": _("Public registrations"), "url": reverse( "plugins:pretix_public_registrations:settings", kwargs={ "event": request.event.slug, "organizer": request.organizer.slug, }, ), "active": url.namespace == "plugins:pretix_public_registrations" and url.url_name == "settings", } ] @receiver(signal=event_copy_data, dispatch_uid="public_registrations_event_copy_data") def event_copy_public_registrations_data(sender, other, item_map, question_map, **_): sender.settings.set( "public_registrations_items", [ str(item_map[int(old_id)].pk) for old_id in other.settings.get("public_registrations_items") ], ) sender.settings.set( "public_registrations_questions", [ str(question_map[int(old_id)].pk) for old_id in other.settings.get("public_registrations_questions") ], )