diff options
author | Magnus Hagander | 2023-06-02 15:37:42 +0000 |
---|---|---|
committer | Magnus Hagander | 2023-06-02 15:37:42 +0000 |
commit | 01214a785959878f6d7dd835347819dbaa888ac1 (patch) | |
tree | 38337993b0bb5f4ad1ecab8587bec1d2af0697b0 /postgresqleu/digisign/backendviews.py | |
parent | 5a8a7681352a19fa81a97ff01f0ad87b1c36231d (diff) |
Add support for digital signature providers
This adds a new type of provider to the system for handling digital
signatures.
Initially the only consumer is conference sponsorships, but it could be
added for other parts of the system as well in the future. Regular
"old-style" sponsorship contracts are still supported, but will gain the
feature to auto-fill sponsor name and VAT number if wanted. The sponsor
signup workflow is adjusted to support either one or both of the two
methods.
Initially the only implementation is Signwell, but the system is made
pluggable just like e.g. the payment providers, so other suppliers can
be added in the future.
This should be considered fairly beta at this point, as several parts of
it cannot be fully tested until a production account is in place. But
the basics are there...
Diffstat (limited to 'postgresqleu/digisign/backendviews.py')
-rw-r--r-- | postgresqleu/digisign/backendviews.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/postgresqleu/digisign/backendviews.py b/postgresqleu/digisign/backendviews.py new file mode 100644 index 00000000..c93885d3 --- /dev/null +++ b/postgresqleu/digisign/backendviews.py @@ -0,0 +1,128 @@ +from django.core.exceptions import PermissionDenied +from django.http import HttpResponse +from django.shortcuts import get_object_or_404, render + +import base64 +import io +import json + +from postgresqleu.util.backendviews import backend_list_editor +from postgresqleu.digisign.models import DigisignProvider, DigisignLog +from postgresqleu.digisign.backendforms import BackendProviderForm +from postgresqleu.digisign.util import digisign_providers +from postgresqleu.digisign.pdfutil import fill_pdf_fields + + +def edit_providers(request, rest): + if not request.user.is_superuser: + raise PermissionDenied("Access denied") + + def _load_formclass(classname): + pieces = classname.split('.') + modname = '.'.join(pieces[:-1]) + classname = pieces[-1] + mod = __import__(modname, fromlist=[classname, ]) + if hasattr(getattr(mod, classname), 'backend_form_class'): + return getattr(mod, classname).backend_form_class + else: + return BackendProviderForm + + u = rest and rest.rstrip('/') or rest + if u and u != '' and u.isdigit(): + p = get_object_or_404(DigisignProvider, pk=u) + formclass = _load_formclass(p.classname) + elif u == 'new': + if '_newformdata' in request.POST or 'classname' in request.POST: + c = request.POST['_newformdata' if '_newformdata' in request.POST else 'classname'] + if c not in digisign_providers: + raise PermissionDenied() + + formclass = _load_formclass(c) + else: + formclass = BackendProviderForm + else: + formclass = BackendProviderForm + + return backend_list_editor(request, + None, + formclass, + rest, + bypass_conference_filter=True, + topadmin='Digital signatures', + return_url='/admin/', + ) + + +def view_provider_log(request, providerid): + if not request.user.is_superuser: + raise PermissionDenied("Access denied") + + provider = get_object_or_404(DigisignProvider, pk=providerid) + + return render(request, 'digisign/digisign_backend_log.html', { + 'log': DigisignLog.objects.filter(provider=provider).order_by('-id')[:100], + 'breadcrumbs': [ + ('/admin/digisign/providers/', 'Digital signature providers'), + ('/admin/digisign/providers/{}/'.format(provider.id), provider.name), + ] + }) + + +def pdf_field_editor(request, conference, pdf, available_fields, fielddata, savecallback=None, breadcrumbs=[]): + import fitz + + if request.method == 'GET' and request.GET.get('current', '0') == '1': + return HttpResponse( + json.dumps(fielddata), + content_type='application/json', + status=200, + ) + elif request.method == 'POST' and 'application/json' in request.META['CONTENT_TYPE']: + # Postback to save all fields + try: + postdata = json.loads(request.body.decode()) + except json.decoder.JSONDecodeError: + return HttpResponse("Invalid json", status=400) + + newdata = { + 'fields': [], + 'fontsize': int(postdata['fontsize']), + } + fieldnames = [fn for fn, fd in available_fields] + for f in postdata['fields']: + if f['field'] in fieldnames: + newdata['fields'].append({ + 'field': f['field'], + 'page': int(f['page']), + 'x': int(f['x']), + 'y': int(f['y']), + }) + else: + return HttpResponse('Invalid field {}'.format(f['field']), status=400) + + newdata['fields'] = sorted(newdata['fields'], key=lambda f: f['page']) + savecallback(fielddata | newdata) + return HttpResponse(json.dumps({'status': 'OK'}), content_type="application/json", status=200) + + # Or we render the base page + + # This is inefficient as hell, but we hope not to have huge PDFs :) Turn the PDF into + # one PNG for each page. + pdf = fitz.open('pdf', bytes(pdf)) + pages = [] + pages = [(pagenum, base64.b64encode(page.getPixmap().getPNGData()).decode()) for pagenum, page in enumerate(pdf.pages())] + + return render(request, 'digisign/pdf_field_editor.html', { + 'conference': conference, + 'breadcrumbs': breadcrumbs, + 'pages': pages, + 'fields': available_fields, + }) + + +def pdf_field_preview(request, conference, pdf, available_fields, fielddata): + pdf = fill_pdf_fields(pdf, available_fields, fielddata) + + resp = HttpResponse(content_type='application/pdf') + resp.write(pdf) + return resp |