Adding a badge token to tickets that grant that.

This commit is contained in:
Víðir Valberg Guðmundsson 2019-07-24 21:08:36 +02:00
parent 04d858adf3
commit b7feb96c9b
9 changed files with 178 additions and 33 deletions

View file

@ -298,7 +298,8 @@ class Order(CreatedUpdatedModel):
def is_partially_ticket_generated(self): def is_partially_ticket_generated(self):
if ( if (
self.orderproductrelation_set.filter(ticket_generated=True).count() != 0 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 # some products are handed out, others are not
return True return True

View file

@ -1,33 +1,29 @@
# Generated by Django 2.2.2 on 2019-07-18 18:52 # Generated by Django 2.2.2 on 2019-07-18 18:52
import hashlib
from django.conf import settings from django.conf import settings
from django.db import migrations from django.db import migrations
from tickets.models import create_ticket_token
def save_tokens(apps, schema_editor): def save_tokens(apps, schema_editor):
ShopTicket = apps.get_model('tickets', 'ShopTicket') ShopTicket = apps.get_model("tickets", "ShopTicket")
SponsorTicket = apps.get_model('tickets', 'SponsorTicket') SponsorTicket = apps.get_model("tickets", "SponsorTicket")
DiscountTicket = apps.get_model('tickets', 'DiscountTicket') DiscountTicket = apps.get_model("tickets", "DiscountTicket")
for model in (ShopTicket, SponsorTicket, DiscountTicket): for model in (ShopTicket, SponsorTicket, DiscountTicket):
for ticket in model.objects.all(): for ticket in model.objects.all():
token = hashlib.sha256( token = create_ticket_token(
"{_id}{secret_key}".format( "{_id}{secret_key}".format(
_id=ticket.uuid, secret_key=settings.SECRET_KEY _id=ticket.uuid, secret_key=settings.SECRET_KEY
).encode("utf-8") ).encode("utf-8")
).hexdigest() )
ticket.token = token ticket.token = token
ticket.save() ticket.save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("tickets", "0006_auto_20190616_1746")]
('tickets', '0006_auto_20190616_1746'),
]
operations = [ operations = [migrations.RunPython(save_tokens)]
migrations.RunPython(save_tokens)
]

View file

@ -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),
),
]

View file

@ -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),
),
]

View file

@ -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)]

View file

@ -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),
),
]

View file

@ -17,16 +17,32 @@ logger = logging.getLogger("bornhack.%s" % __name__)
class TicketType(CampRelatedModel, UUIDModel): class TicketType(CampRelatedModel, UUIDModel):
name = models.TextField() name = models.TextField()
camp = models.ForeignKey("camps.Camp", on_delete=models.PROTECT) camp = models.ForeignKey("camps.Camp", on_delete=models.PROTECT)
includes_badge = models.BooleanField(default=False)
def __str__(self): def __str__(self):
return "{} ({})".format(self.name, self.camp.title) 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): class BaseTicket(CampRelatedModel, UUIDModel):
ticket_type = models.ForeignKey("TicketType", on_delete=models.PROTECT) ticket_type = models.ForeignKey("TicketType", on_delete=models.PROTECT)
used = models.BooleanField(default=False) used = models.BooleanField(default=False)
badge_handed_out = models.BooleanField(default=False) badge_handed_out = models.BooleanField(default=False)
token = models.CharField(max_length=64) token = models.CharField(max_length=64)
badge_token = models.CharField(max_length=64)
class Meta: class Meta:
abstract = True abstract = True
@ -37,29 +53,31 @@ class BaseTicket(CampRelatedModel, UUIDModel):
def save(self, **kwargs): def save(self, **kwargs):
self.token = self._get_token() self.token = self._get_token()
self.badge_token = self._get_token()
super().save(**kwargs) super().save(**kwargs)
def _get_token(self): def _get_token(self):
return hashlib.sha256( return create_ticket_token(
"{_id}{secret_key}".format( "{_id}{secret_key}".format(
_id=self.uuid, secret_key=settings.SECRET_KEY _id=self.uuid, secret_key=settings.SECRET_KEY
).encode("utf-8") ).encode("utf-8")
).hexdigest() )
def get_qr_code_base64(self): def _get_badge_token(self):
qr = qrcode.make( return create_ticket_token(
self._get_token(), "{_id}{secret_key}-badge".format(
version=1, _id=self.uuid, secret_key=settings.SECRET_KEY
error_correction=qrcode.constants.ERROR_CORRECT_H, ).encode("utf-8")
).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_qr_code_url(self): def get_qr_code_url(self):
return "data:image/png;base64,{}".format( 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): def generate_pdf(self):

View file

@ -1,6 +1,5 @@
{% load static from staticfiles %} {% load static from staticfiles %}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<table style="width:100%;"> <table style="width:100%;">
<tr> <tr>
<td style="width: 75%;">&nbsp;</td> <td style="width: 75%;">&nbsp;</td>
@ -25,11 +24,38 @@
<h3>Sponsor: {{ ticket.sponsor.name }} </h3> <h3>Sponsor: {{ ticket.sponsor.name }} </h3>
<img src="{% static 'img/sponsors/' %}{{ sponsor.logo_filename }}"></img> <img src="{% static 'img/sponsors/' %}{{ sponsor.logo_filename }}"></img>
{% endif %} {% endif %}
{% if ticket.used %} {% if ticket.used %}
<h2>This ticket has been used.</h2> <h2>This ticket has been used.</h2>
{% endif %} {% endif %}
<center> <center>
<img src="{{ ticket.get_qr_code_url }}"></img> <img src="{{ ticket.get_qr_code_url }}"></img>
<p>Ticket #{{ ticket.pk }}</p> <p>{{ ticket.token }}</p>
</center> </center>
{% if ticket.ticket_type.includes_badge %}
<div style="display:block; clear:both; page-break-after:always;"></div>
<table style="width:100%;">
<tr>
<td style="width: 75%;">&nbsp;</td>
<td>
<h3>
{{ ticket.created|date:"b jS, Y" }}<br>
</h3>
</td>
</tr>
</table>
<br />
<h2>Badge voucher</h2>
<center>
<img src="{{ ticket.get_qr_badge_code_url }}"></img>
<p>{{ ticket.badge_token }}</p>
</center>
{% endif %}

View file

@ -12,7 +12,9 @@ logger = logging.getLogger("bornhack.%s" % __name__)
def generate_pdf_letter(filename, template, formatdict): 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 # conjure up a fake request for PDFTemplateResponse
request = RequestFactory().get("/") request = RequestFactory().get("/")
@ -47,9 +49,9 @@ def generate_pdf_letter(filename, template, formatdict):
# add the watermark to all pages # add the watermark to all pages
for pagenum in range(pdfreader.getNumPages()): for pagenum in range(pdfreader.getNumPages()):
page = watermark.getPage(0) page = pdfreader.getPage(pagenum)
try: try:
page.mergePage(pdfreader.getPage(pagenum)) page.mergePage(watermark.getPage(0))
except ValueError: except ValueError:
# watermark pdf might be broken? # watermark pdf might be broken?
return False return False
@ -65,4 +67,3 @@ def generate_pdf_letter(filename, template, formatdict):
returnfile = io.BytesIO() returnfile = io.BytesIO()
finalpdf.write(returnfile) finalpdf.write(returnfile)
return returnfile return returnfile