diff --git a/apiserver/apiserver/api/utils.py b/apiserver/apiserver/api/utils.py index 0bf1dea..b6f6ba6 100644 --- a/apiserver/apiserver/api/utils.py +++ b/apiserver/apiserver/api/utils.py @@ -1,9 +1,13 @@ -from rest_framework.exceptions import ValidationError import datetime +import io +from rest_framework.exceptions import ValidationError from dateutil import relativedelta from uuid import uuid4 from PIL import Image from bleach.sanitizer import Cleaner +from PyPDF2 import PdfFileWriter, PdfFileReader +from reportlab.pdfgen import canvas +from reportlab.lib.pagesizes import letter from django.db.models import Sum @@ -239,3 +243,42 @@ def link_old_member(data, user): for t in training: t.user = user t.save() + + +BLANK_FORM = 'misc/blank_member_form.pdf' +def generate_application_pdf(member): + packet = io.BytesIO() + + can = canvas.Canvas(packet, pagesize=letter) + can.drawRightString(580, 770, '{} {} ({})'.format( + member['first_name'], + member['last_name'], + member['id'], + )) + can.drawString(34, 683, member['first_name']) + can.drawString(218, 683, member['last_name']) + can.drawString(403, 683, member['preferred_name']) + can.drawString(34, 654, member['street_address']) + can.drawString(275, 654, member['city']) + can.drawString(459, 654, member['postal_code']) + can.drawString(34, 626, member['email']) + can.drawString(332, 626, member['phone']) + can.drawString(34, 570, member['emergency_contact_name']) + can.drawString(332, 570, member['emergency_contact_phone']) + can.save() + + packet.seek(0) + new_pdf = PdfFileReader(packet) + existing_pdf = PdfFileReader(open(BLANK_FORM, 'rb')) + output = PdfFileWriter() + page = existing_pdf.getPage(0) + page.mergePage(new_pdf.getPage(0)) + output.addPage(page) + page = existing_pdf.getPage(1) + output.addPage(page) + page = existing_pdf.getPage(2) + output.addPage(page) + + outputStream = io.BytesIO() + output.write(outputStream) + return outputStream diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index cabe35a..4c267b3 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -1,6 +1,8 @@ from django.contrib.auth.models import User, Group from django.shortcuts import get_object_or_404 from django.db.models import Max +from django.http import HttpResponse +from django.core.files.base import File from rest_framework import viewsets, views, mixins, generics, exceptions from rest_framework.decorators import action from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS @@ -110,7 +112,7 @@ class MemberViewSet(Base, Retrieve, Update): def pause(self, request, pk=None): if not is_admin_director(self.request.user): raise exceptions.PermissionDenied() - member = get_object_or_404(self.queryset, pk=pk) + member = self.get_object() member.paused_date = datetime.date.today() member.save() return Response(200) @@ -119,13 +121,20 @@ class MemberViewSet(Base, Retrieve, Update): def unpause(self, request, pk=None): if not is_admin_director(self.request.user): raise exceptions.PermissionDenied() - member = get_object_or_404(self.queryset, pk=pk) + member = self.get_object() member.current_start_date = datetime.date.today() member.paused_date = None member.save() utils.tally_membership_months(member) return Response(200) + @action(detail=True) + def forms(self, request, pk=None): + member = self.get_object() + serializer = self.get_serializer(member) + form = utils.generate_application_pdf(serializer.data) + return HttpResponse(File(form), content_type='application/pdf') + class CardViewSet(Base, Create, Retrieve, Update, Destroy): permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin] diff --git a/apiserver/docs/source/api.rst b/apiserver/docs/source/api.rst index 323e1ee..facbd15 100644 --- a/apiserver/docs/source/api.rst +++ b/apiserver/docs/source/api.rst @@ -343,6 +343,18 @@ Pausing / Unpausing Member :status 200: +Member PDF Forms +++++++++++++++++ + +.. http:get:: /members/(id)/forms/ + + Generate member's application PDF forms. Users can only view their own, + admins can view anyone's. + + :param id: + + :requestheader Authorization: ``Token `` + Search ------ diff --git a/apiserver/misc/blank_member_form.pdf b/apiserver/misc/blank_member_form.pdf new file mode 100644 index 0000000..da7ef9c Binary files /dev/null and b/apiserver/misc/blank_member_form.pdf differ diff --git a/apiserver/requirements.txt b/apiserver/requirements.txt index 2c30f3d..d6fca8b 100644 --- a/apiserver/requirements.txt +++ b/apiserver/requirements.txt @@ -23,10 +23,12 @@ Pillow==7.0.0 pycparser==2.19 Pygments==2.5.2 pyparsing==2.4.6 +PyPDF2==1.26.0 python-dateutil==2.8.1 python-Levenshtein==0.12.0 python3-openid==3.1.0 pytz==2019.3 +reportlab==3.5.34 requests==2.22.0 requests-oauthlib==1.3.0 six==1.13.0