diff --git a/src/shop/models.py b/src/shop/models.py index 07091cf4..cda98870 100644 --- a/src/shop/models.py +++ b/src/shop/models.py @@ -298,7 +298,8 @@ class Order(CreatedUpdatedModel): def is_partially_ticket_generated(self): if ( self.orderproductrelation_set.filter(ticket_generated=True).count() != 0 - and self.orderproductrelation_set.filter(ticket_generated=False).count() != 0 + and self.orderproductrelation_set.filter(ticket_generated=False).count() + != 0 ): # some products are handed out, others are not return True diff --git a/src/tickets/migrations/0007_save_token_to_db.py b/src/tickets/migrations/0007_save_token_to_db.py index aba23f66..cef68d1e 100644 --- a/src/tickets/migrations/0007_save_token_to_db.py +++ b/src/tickets/migrations/0007_save_token_to_db.py @@ -1,33 +1,29 @@ # Generated by Django 2.2.2 on 2019-07-18 18:52 -import hashlib - from django.conf import settings from django.db import migrations +from tickets.models import create_ticket_token + def save_tokens(apps, schema_editor): - ShopTicket = apps.get_model('tickets', 'ShopTicket') - SponsorTicket = apps.get_model('tickets', 'SponsorTicket') - DiscountTicket = apps.get_model('tickets', 'DiscountTicket') + ShopTicket = apps.get_model("tickets", "ShopTicket") + SponsorTicket = apps.get_model("tickets", "SponsorTicket") + DiscountTicket = apps.get_model("tickets", "DiscountTicket") for model in (ShopTicket, SponsorTicket, DiscountTicket): for ticket in model.objects.all(): - token = hashlib.sha256( + token = create_ticket_token( "{_id}{secret_key}".format( _id=ticket.uuid, secret_key=settings.SECRET_KEY ).encode("utf-8") - ).hexdigest() + ) ticket.token = token ticket.save() class Migration(migrations.Migration): - dependencies = [ - ('tickets', '0006_auto_20190616_1746'), - ] + dependencies = [("tickets", "0006_auto_20190616_1746")] - operations = [ - migrations.RunPython(save_tokens) - ] + operations = [migrations.RunPython(save_tokens)] diff --git a/src/tickets/migrations/0009_tickettype_includes_badge.py b/src/tickets/migrations/0009_tickettype_includes_badge.py new file mode 100644 index 00000000..82a5da1b --- /dev/null +++ b/src/tickets/migrations/0009_tickettype_includes_badge.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-07-23 20:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0008_auto_20190718_2055'), + ] + + operations = [ + migrations.AddField( + model_name='tickettype', + name='includes_badge', + field=models.BooleanField(default=False), + ), + ] diff --git a/src/tickets/migrations/0010_auto_20190724_2037.py b/src/tickets/migrations/0010_auto_20190724_2037.py new file mode 100644 index 00000000..414dfbd5 --- /dev/null +++ b/src/tickets/migrations/0010_auto_20190724_2037.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.3 on 2019-07-24 18:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0009_tickettype_includes_badge'), + ] + + operations = [ + migrations.AddField( + model_name='discountticket', + name='badge_token', + field=models.CharField(max_length=64, null=True), + ), + migrations.AddField( + model_name='shopticket', + name='badge_token', + field=models.CharField(max_length=64, null=True), + ), + migrations.AddField( + model_name='sponsorticket', + name='badge_token', + field=models.CharField(max_length=64, null=True), + ), + ] diff --git a/src/tickets/migrations/0011_save_badge_token_to_db.py b/src/tickets/migrations/0011_save_badge_token_to_db.py new file mode 100644 index 00000000..dbc0883d --- /dev/null +++ b/src/tickets/migrations/0011_save_badge_token_to_db.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.3 on 2019-07-24 18:37 +from django.conf import settings +from django.db import migrations + +from tickets.models import create_ticket_token + + +def save_badge_tokens(apps, schema_editor): + ShopTicket = apps.get_model("tickets", "ShopTicket") + SponsorTicket = apps.get_model("tickets", "SponsorTicket") + DiscountTicket = apps.get_model("tickets", "DiscountTicket") + + for model in (ShopTicket, SponsorTicket, DiscountTicket): + + for ticket in model.objects.all(): + badge_token = create_ticket_token( + "{_id}{secret_key}-badge".format( + _id=ticket.uuid, secret_key=settings.SECRET_KEY + ).encode("utf-8") + ) + ticket.badge_token = badge_token + ticket.save() + + +class Migration(migrations.Migration): + + dependencies = [("tickets", "0010_auto_20190724_2037")] + + operations = [migrations.RunPython(save_badge_tokens)] diff --git a/src/tickets/migrations/0012_auto_20190724_2037.py b/src/tickets/migrations/0012_auto_20190724_2037.py new file mode 100644 index 00000000..ae3ce0db --- /dev/null +++ b/src/tickets/migrations/0012_auto_20190724_2037.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.3 on 2019-07-24 18:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0011_save_badge_token_to_db'), + ] + + operations = [ + migrations.AlterField( + model_name='discountticket', + name='badge_token', + field=models.CharField(max_length=64), + ), + migrations.AlterField( + model_name='shopticket', + name='badge_token', + field=models.CharField(max_length=64), + ), + migrations.AlterField( + model_name='sponsorticket', + name='badge_token', + field=models.CharField(max_length=64), + ), + ] diff --git a/src/tickets/models.py b/src/tickets/models.py index 49ffeab7..36b4d969 100644 --- a/src/tickets/models.py +++ b/src/tickets/models.py @@ -17,16 +17,32 @@ logger = logging.getLogger("bornhack.%s" % __name__) class TicketType(CampRelatedModel, UUIDModel): name = models.TextField() camp = models.ForeignKey("camps.Camp", on_delete=models.PROTECT) + includes_badge = models.BooleanField(default=False) def __str__(self): return "{} ({})".format(self.name, self.camp.title) +def create_ticket_token(string): + return hashlib.sha256(string).hexdigest() + + +def qr_code_base64(token): + qr = qrcode.make( + token, version=1, error_correction=qrcode.constants.ERROR_CORRECT_H + ).resize((250, 250)) + file_like = io.BytesIO() + qr.save(file_like, format="png") + qrcode_base64 = base64.b64encode(file_like.getvalue()) + return qrcode_base64 + + class BaseTicket(CampRelatedModel, UUIDModel): ticket_type = models.ForeignKey("TicketType", on_delete=models.PROTECT) used = models.BooleanField(default=False) badge_handed_out = models.BooleanField(default=False) token = models.CharField(max_length=64) + badge_token = models.CharField(max_length=64) class Meta: abstract = True @@ -37,29 +53,31 @@ class BaseTicket(CampRelatedModel, UUIDModel): def save(self, **kwargs): self.token = self._get_token() + self.badge_token = self._get_token() super().save(**kwargs) def _get_token(self): - return hashlib.sha256( + return create_ticket_token( "{_id}{secret_key}".format( _id=self.uuid, secret_key=settings.SECRET_KEY ).encode("utf-8") - ).hexdigest() + ) - def get_qr_code_base64(self): - qr = qrcode.make( - self._get_token(), - version=1, - error_correction=qrcode.constants.ERROR_CORRECT_H, - ).resize((250, 250)) - file_like = io.BytesIO() - qr.save(file_like, format="png") - qrcode_base64 = base64.b64encode(file_like.getvalue()) - return qrcode_base64 + def _get_badge_token(self): + return create_ticket_token( + "{_id}{secret_key}-badge".format( + _id=self.uuid, secret_key=settings.SECRET_KEY + ).encode("utf-8") + ) def get_qr_code_url(self): return "data:image/png;base64,{}".format( - self.get_qr_code_base64().decode("utf-8") + qr_code_base64(self._get_token()).decode("utf-8") + ) + + def get_qr_badge_code_url(self): + return "data:image/png;base64,{}".format( + qr_code_base64(self._get_badge_token()).decode("utf-8") ) def generate_pdf(self): diff --git a/src/tickets/templates/pdf/ticket.html b/src/tickets/templates/pdf/ticket.html index d8e3eaa8..57ed3957 100644 --- a/src/tickets/templates/pdf/ticket.html +++ b/src/tickets/templates/pdf/ticket.html @@ -1,6 +1,5 @@ {% load static from staticfiles %} - @@ -25,11 +24,38 @@

Sponsor: {{ ticket.sponsor.name }}

{% endif %} + {% if ticket.used %}

This ticket has been used.

{% endif %}
-

Ticket #{{ ticket.pk }}

+

{{ ticket.token }}

+ +{% if ticket.ticket_type.includes_badge %} +
+ +
 
+ + + + +
  +

+ {{ ticket.created|date:"b jS, Y" }}
+

+
+
+ +

Badge voucher

+ +
+ +

{{ ticket.badge_token }}

+
+ +{% endif %} + + diff --git a/src/utils/pdf.py b/src/utils/pdf.py index 345aa03a..f9d43079 100644 --- a/src/utils/pdf.py +++ b/src/utils/pdf.py @@ -12,7 +12,9 @@ logger = logging.getLogger("bornhack.%s" % __name__) def generate_pdf_letter(filename, template, formatdict): - logger.debug("Generating PDF with filename %s and template %s" % (filename, template)) + logger.debug( + "Generating PDF with filename %s and template %s" % (filename, template) + ) # conjure up a fake request for PDFTemplateResponse request = RequestFactory().get("/") @@ -47,9 +49,9 @@ def generate_pdf_letter(filename, template, formatdict): # add the watermark to all pages for pagenum in range(pdfreader.getNumPages()): - page = watermark.getPage(0) + page = pdfreader.getPage(pagenum) try: - page.mergePage(pdfreader.getPage(pagenum)) + page.mergePage(watermark.getPage(0)) except ValueError: # watermark pdf might be broken? return False @@ -65,4 +67,3 @@ def generate_pdf_letter(filename, template, formatdict): returnfile = io.BytesIO() finalpdf.write(returnfile) return returnfile -