Add QR codes for pseudonymization ID

This commit is contained in:
Raphael Michel
2018-05-28 16:55:54 +02:00
parent 550ff4ff18
commit eb6063cc2d
10 changed files with 114 additions and 12 deletions

View File

@@ -128,7 +128,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
model = OrderPosition
fields = ('id', 'order', 'positionid', 'item', 'variation', 'price', 'attendee_name', 'attendee_email',
'voucher', 'tax_rate', 'tax_value', 'secret', 'addon_to', 'subevent', 'checkins', 'downloads',
'answers', 'tax_rule')
'answers', 'tax_rule', 'pseudonymization_id')
class OrderFeeSerializer(I18nAwareModelSerializer):

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2018-05-28 14:32
from __future__ import unicode_literals
from django.db import migrations, models
from django.utils.crypto import get_random_string
def set_pids(apps, schema_editor):
OrderPosition = apps.get_model('pretixbase', 'OrderPosition') # noqa
taken = set()
charset = list('ABCDEFGHJKLMNPQRSTUVWXYZ3789')
for op in OrderPosition.objects.iterator():
while True:
code = get_random_string(length=10, allowed_chars=charset)
if code not in taken:
op.pseudonymization_id = code
taken.add(code)
break
op.save(update_fields=['pseudonymization_id'])
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0092_auto_20180511_1224'),
]
operations = [
migrations.AddField(
model_name='orderposition',
name='pseudonymization_id',
field=models.CharField(db_index=True, max_length=16, null=True, unique=True),
),
migrations.RunPython(
set_pids,
migrations.RunPython.noop,
),
migrations.AlterField(
model_name='orderposition',
name='pseudonymization_id',
field=models.CharField(db_index=True, default='', max_length=16, unique=True),
preserve_default=False,
),
]

View File

@@ -835,6 +835,11 @@ class OrderPosition(AbstractPosition):
verbose_name=_('Tax value')
)
secret = models.CharField(max_length=64, default=generate_position_secret, db_index=True)
pseudonymization_id = models.CharField(
max_length=16,
unique=True,
db_index=True
)
class Meta:
verbose_name = _("Order position")
@@ -916,8 +921,24 @@ class OrderPosition(AbstractPosition):
if self.pk is None:
while OrderPosition.objects.filter(secret=self.secret).exists():
self.secret = generate_position_secret()
if not self.pseudonymization_id:
self.assign_pseudonymization_id()
return super().save(*args, **kwargs)
def assign_pseudonymization_id(self):
# This omits some character pairs completely because they are hard to read even on screens (1/I and O/0)
# and includes only one of two characters for some pairs because they are sometimes hard to distinguish in
# handwriting (2/Z, 4/A, 5/S, 6/G). This allows for better detection e.g. in incoming wire transfers that
# might include OCR'd handwritten text
charset = list('ABCDEFGHJKLMNPQRSTUVWXYZ3789')
while True:
code = get_random_string(length=10, allowed_chars=charset)
if not OrderPosition.objects.filter(pseudonymization_id=code).exists():
self.pseudonymization_id = code
return
class CartPosition(AbstractPosition):
"""

View File

@@ -211,8 +211,14 @@ class Renderer:
pdfmetrics.registerFont(TTFont(family + ' B I', finders.find(styles['bolditalic']['truetype'])))
def _draw_barcodearea(self, canvas: Canvas, op: OrderPosition, o: dict):
content = o.get('content', 'secret')
if content == 'secret':
content = op.secret
elif content == 'pseudonymization_id':
content = op.pseudonymization_id
reqs = float(o['size']) * mm
qrw = QrCodeWidget(op.secret, barLevel='H', barHeight=reqs, barWidth=reqs)
qrw = QrCodeWidget(content, barLevel='H', barHeight=reqs, barWidth=reqs)
d = Drawing(reqs, reqs)
d.add(qrw)
qr_x = float(o['left']) * mm

View File

@@ -317,9 +317,15 @@
<span class="fa fa-font"></span>
{% trans "Text" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-qrcode" disabled>
<button class="btn btn-default btn-block" id="editor-add-qrcode" data-content="secret" disabled>
<span class="fa fa-qrcode"></span>
{% trans "QR code area" %}
{% trans "QR code for Check-In" %}
</button>
<button class="btn btn-default btn-block" id="editor-add-qrcode-lead"
data-content="pseudonymization_id"
disabled>
<span class="fa fa-qrcode"></span>
{% trans "QR code for Lead Scanning" %}
</button>
</div>
</div>

View File

@@ -18,7 +18,11 @@ fabric.Barcodearea = fabric.util.createClass(fabric.Rect, {
ctx.font = '16px Helvetica';
ctx.fillStyle = '#fff';
ctx.fillText(gettext('QR Code'), -this.width / 2, -this.height / 2 + 20);
if (this.content === "pseudonymization_id") {
ctx.fillText(gettext('Lead Scan QR'), -this.width / 2, -this.height / 2 + 20);
} else {
ctx.fillText(gettext('Check-in QR'), -this.width / 2, -this.height / 2 + 20);
}
},
});
fabric.Barcodearea.fromObject = function (object, callback, forceAsync) {
@@ -112,7 +116,8 @@ var editor = {
type: "barcodearea",
left: editor._px2mm(left).toFixed(2),
bottom: editor._px2mm(editor.pdf_viewport.height - o.height * o.scaleY - top).toFixed(2),
size: editor._px2mm(o.height * o.scaleY).toFixed(2)
size: editor._px2mm(o.height * o.scaleY).toFixed(2),
content: o.content,
});
}
}
@@ -122,6 +127,7 @@ var editor = {
_add_from_data: function (d) {
if (d.type === "barcodearea") {
o = editor._add_qrcode();
o.content = d.content;
o.scaleToHeight(editor._mm2px(d.size));
} else if (d.type === "textarea" || o.type === "text") {
o = editor._add_text();
@@ -418,6 +424,7 @@ var editor = {
lockRotation: true,
lockUniScaling: true,
fill: '#666',
content: $(this).attr("data-content"),
});
rect.setControlsVisibility({'mtr': false});
editor.fabric.add(rect);
@@ -645,7 +652,7 @@ var editor = {
editor.$fcv = $("#fabric-canvas");
editor.$cva = $("#editor-canvas-area");
editor._load_pdf();
$("#editor-add-qrcode").click(editor._add_qrcode);
$("#editor-add-qrcode, #editor-add-qrcode-lead").click(editor._add_qrcode);
$("#editor-add-text").click(editor._add_text);
editor.$cva.get(0).tabIndex = 1000;
editor.$cva.on("keydown", editor._on_keydown);