Statically serve member PDF forms instead, add link
This commit is contained in:
parent
0c1f82a3c7
commit
7eb46f39db
|
@ -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)
|
||||||
|
|
|
@ -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',
|
||||||
]
|
]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
------
|
------
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user