Statically serve member PDF forms instead, add link

This commit is contained in:
Tanner Collin 2020-01-26 10:39:59 +00:00
parent 0c1f82a3c7
commit 7eb46f39db
6 changed files with 51 additions and 38 deletions

View File

@ -11,6 +11,7 @@ class Member(models.Model):
photo_large = models.CharField(max_length=64, blank=True, null=True) photo_large = models.CharField(max_length=64, blank=True, null=True)
photo_medium = models.CharField(max_length=64, blank=True, null=True) photo_medium = models.CharField(max_length=64, blank=True, null=True)
photo_small = models.CharField(max_length=64, blank=True, null=True) photo_small = models.CharField(max_length=64, blank=True, null=True)
member_forms = models.CharField(max_length=64, blank=True, null=True)
set_details = models.BooleanField(default=False) set_details = models.BooleanField(default=False)
first_name = models.CharField(max_length=32) first_name = models.CharField(max_length=32)

View File

@ -114,6 +114,7 @@ class MemberSerializer(serializers.ModelSerializer):
'photo_large', 'photo_large',
'photo_medium', 'photo_medium',
'photo_small', 'photo_small',
'member_forms',
'user', 'user',
'old_email', 'old_email',
] ]
@ -150,6 +151,7 @@ class AdminMemberSerializer(MemberSerializer):
'photo_large', 'photo_large',
'photo_medium', 'photo_medium',
'photo_small', 'photo_small',
'member_forms',
'user', 'user',
'old_email', 'old_email',
] ]

View File

@ -11,13 +11,16 @@ from reportlab.lib.pagesizes import letter
from django.db.models import Sum from django.db.models import Sum
from . import models from . import models, serializers
try: try:
from . import old_models from . import old_models
except ImportError: except ImportError:
print('Running without old portal data...') print('Running without old portal data...')
old_models = None old_models = None
STATIC_FOLDER = 'data/static/'
def num_months_spanned(d1, d2): def num_months_spanned(d1, d2):
''' '''
Return number of month thresholds two dates span. Return number of month thresholds two dates span.
@ -135,7 +138,6 @@ def gen_search_strings():
search_strings[string] = m.id search_strings[string] = m.id
STATIC_FOLDER = 'data/static/'
LARGE_SIZE = 1080 LARGE_SIZE = 1080
MEDIUM_SIZE = 220 MEDIUM_SIZE = 220
SMALL_SIZE = 110 SMALL_SIZE = 110
@ -246,25 +248,27 @@ def link_old_member(data, user):
BLANK_FORM = 'misc/blank_member_form.pdf' BLANK_FORM = 'misc/blank_member_form.pdf'
def generate_application_pdf(member): def gen_member_forms(member):
packet = io.BytesIO() serializer = serializers.MemberSerializer(member)
data = serializer.data
packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=letter) can = canvas.Canvas(packet, pagesize=letter)
can.drawRightString(580, 770, '{} {} ({})'.format( can.drawRightString(580, 770, '{} {} ({})'.format(
member['first_name'], data['first_name'],
member['last_name'], data['last_name'],
member['id'], data['id'],
)) ))
can.drawString(34, 683, member['first_name']) can.drawString(34, 683, data['first_name'])
can.drawString(218, 683, member['last_name']) can.drawString(218, 683, data['last_name'])
can.drawString(403, 683, member['preferred_name']) can.drawString(403, 683, data['preferred_name'])
can.drawString(34, 654, member['street_address']) can.drawString(34, 654, data['street_address'])
can.drawString(275, 654, member['city']) can.drawString(275, 654, data['city'])
can.drawString(459, 654, member['postal_code']) can.drawString(459, 654, data['postal_code'])
can.drawString(34, 626, member['email']) can.drawString(34, 626, data['email'])
can.drawString(332, 626, member['phone']) can.drawString(332, 626, data['phone'])
can.drawString(34, 570, member['emergency_contact_name']) can.drawString(34, 570, data['emergency_contact_name'])
can.drawString(332, 570, member['emergency_contact_phone']) can.drawString(332, 570, data['emergency_contact_phone'])
can.save() can.save()
packet.seek(0) packet.seek(0)
@ -279,6 +283,9 @@ def generate_application_pdf(member):
page = existing_pdf.getPage(2) page = existing_pdf.getPage(2)
output.addPage(page) output.addPage(page)
outputStream = io.BytesIO() file_name = str(uuid4()) + '.pdf'
outputStream = open(STATIC_FOLDER + file_name, 'wb')
output.write(outputStream) output.write(outputStream)
return outputStream
member.member_forms = file_name
member.save()

View File

@ -103,10 +103,12 @@ class MemberViewSet(Base, Retrieve, Update):
def perform_create(self, serializer): def perform_create(self, serializer):
member = serializer.save() member = serializer.save()
utils.tally_membership_months(member) utils.tally_membership_months(member)
utils.gen_member_forms(member)
def perform_update(self, serializer): def perform_update(self, serializer):
member = serializer.save() member = serializer.save()
utils.tally_membership_months(member) utils.tally_membership_months(member)
utils.gen_member_forms(member)
@action(detail=True, methods=['post']) @action(detail=True, methods=['post'])
def pause(self, request, pk=None): def pause(self, request, pk=None):
@ -128,13 +130,6 @@ class MemberViewSet(Base, Retrieve, Update):
utils.tally_membership_months(member) utils.tally_membership_months(member)
return Response(200) 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): class CardViewSet(Base, Create, Retrieve, Update, Destroy):
permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin] permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin]

View File

@ -93,6 +93,7 @@ Full User
"photo_large": "uuid.jpg", "photo_large": "uuid.jpg",
"photo_medium": "uuid.jpg", "photo_medium": "uuid.jpg",
"photo_small": "uuid.jpg", "photo_small": "uuid.jpg",
"member_forms": "uuid.pdf",
"set_details": true, "set_details": true,
"first_name": "Tanner", "first_name": "Tanner",
"last_name": "Collin", "last_name": "Collin",
@ -226,6 +227,7 @@ Member Details
"photo_large": "uuid.jpg", "photo_large": "uuid.jpg",
"photo_medium": "uuid.jpg", "photo_medium": "uuid.jpg",
"photo_small": "uuid.jpg", "photo_small": "uuid.jpg",
"member_forms": "uuid.pdf",
"set_details": true, "set_details": true,
"first_name": "Tanner", "first_name": "Tanner",
"last_name": "Collin", "last_name": "Collin",
@ -253,6 +255,7 @@ Member Details
object to users when they claim their old member. object to users when they claim their old member.
:json photo\_\*: Should be served by nginx on the ``static`` subdomain. Refers :json photo\_\*: Should be served by nginx on the ``static`` subdomain. Refers
to photo filenames in the ``apiserver/data/static`` directory. to photo filenames in the ``apiserver/data/static`` directory.
:json member_forms: Should be served by nginx on the ``static`` subdomain.
:json status: Derived by subtracting today's date from expire_date. More :json status: Derived by subtracting today's date from expire_date. More
than one month: Prepaid, less than one month: Current, less than one than one month: Prepaid, less than one month: Current, less than one
month behind: Due, more than one month behind: Overdue. Members more month behind: Due, more than one month behind: Overdue. Members more
@ -273,6 +276,8 @@ Edit Member Details
Set member details. Set member details.
Member PDF forms will automatically be regenerated on any change.
**Users** **Users**
Can only set certain fields of their own member. Can only set certain fields of their own member.
@ -343,18 +348,6 @@ Pausing / Unpausing Member
:status 200: :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 <token>``
Search Search
------ ------

View File

@ -44,6 +44,15 @@ function MemberInfo(props) {
</Grid.Column> </Grid.Column>
</Grid> </Grid>
{!member.photo_medium && <Message>
<Message.Header>Welcome, new member!</Message.Header>
<p>
<a href={staticUrl + '/' + member.member_forms} target='_blank'>
Click here
</a> to view your appliction forms.
</p>
</Message>}
{!member.photo_medium && <Message warning> {!member.photo_medium && <Message warning>
<Message.Header>Please set a member photo!</Message.Header> <Message.Header>Please set a member photo!</Message.Header>
<p>Visit the <Link to='/account'>account settings</Link> page to set one.</p> <p>Visit the <Link to='/account'>account settings</Link> page to set one.</p>
@ -75,6 +84,12 @@ function MemberInfo(props) {
</Table.Body> </Table.Body>
</BasicTable> </BasicTable>
{member.photo_medium && <p>
<a href={staticUrl + '/' + member.member_forms} target='_blank'>
View application forms
</a>
</p>}
<Header size='medium'>Latest Transactions</Header> <Header size='medium'>Latest Transactions</Header>
<BasicTable> <BasicTable>
<Table.Body> <Table.Body>