diff --git a/apiserver/apiserver/api/models.py b/apiserver/apiserver/api/models.py index e21269e..ba27ce1 100644 --- a/apiserver/apiserver/api/models.py +++ b/apiserver/apiserver/api/models.py @@ -11,6 +11,7 @@ class Member(models.Model): photo_large = 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) + member_forms = models.CharField(max_length=64, blank=True, null=True) set_details = models.BooleanField(default=False) first_name = models.CharField(max_length=32) diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index 3a6a7a8..5b44b31 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -114,6 +114,7 @@ class MemberSerializer(serializers.ModelSerializer): 'photo_large', 'photo_medium', 'photo_small', + 'member_forms', 'user', 'old_email', ] @@ -150,6 +151,7 @@ class AdminMemberSerializer(MemberSerializer): 'photo_large', 'photo_medium', 'photo_small', + 'member_forms', 'user', 'old_email', ] diff --git a/apiserver/apiserver/api/utils.py b/apiserver/apiserver/api/utils.py index b6f6ba6..095cff9 100644 --- a/apiserver/apiserver/api/utils.py +++ b/apiserver/apiserver/api/utils.py @@ -11,13 +11,16 @@ from reportlab.lib.pagesizes import letter from django.db.models import Sum -from . import models +from . import models, serializers try: from . import old_models except ImportError: print('Running without old portal data...') old_models = None +STATIC_FOLDER = 'data/static/' + + def num_months_spanned(d1, d2): ''' Return number of month thresholds two dates span. @@ -135,7 +138,6 @@ def gen_search_strings(): search_strings[string] = m.id -STATIC_FOLDER = 'data/static/' LARGE_SIZE = 1080 MEDIUM_SIZE = 220 SMALL_SIZE = 110 @@ -246,25 +248,27 @@ def link_old_member(data, user): BLANK_FORM = 'misc/blank_member_form.pdf' -def generate_application_pdf(member): - packet = io.BytesIO() +def gen_member_forms(member): + serializer = serializers.MemberSerializer(member) + data = serializer.data + packet = io.BytesIO() can = canvas.Canvas(packet, pagesize=letter) can.drawRightString(580, 770, '{} {} ({})'.format( - member['first_name'], - member['last_name'], - member['id'], + data['first_name'], + data['last_name'], + data['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.drawString(34, 683, data['first_name']) + can.drawString(218, 683, data['last_name']) + can.drawString(403, 683, data['preferred_name']) + can.drawString(34, 654, data['street_address']) + can.drawString(275, 654, data['city']) + can.drawString(459, 654, data['postal_code']) + can.drawString(34, 626, data['email']) + can.drawString(332, 626, data['phone']) + can.drawString(34, 570, data['emergency_contact_name']) + can.drawString(332, 570, data['emergency_contact_phone']) can.save() packet.seek(0) @@ -279,6 +283,9 @@ def generate_application_pdf(member): page = existing_pdf.getPage(2) output.addPage(page) - outputStream = io.BytesIO() + file_name = str(uuid4()) + '.pdf' + outputStream = open(STATIC_FOLDER + file_name, 'wb') output.write(outputStream) - return outputStream + + member.member_forms = file_name + member.save() diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index 4c267b3..6fda977 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -103,10 +103,12 @@ class MemberViewSet(Base, Retrieve, Update): def perform_create(self, serializer): member = serializer.save() utils.tally_membership_months(member) + utils.gen_member_forms(member) def perform_update(self, serializer): member = serializer.save() utils.tally_membership_months(member) + utils.gen_member_forms(member) @action(detail=True, methods=['post']) def pause(self, request, pk=None): @@ -128,13 +130,6 @@ class MemberViewSet(Base, Retrieve, Update): 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 facbd15..aeeb316 100644 --- a/apiserver/docs/source/api.rst +++ b/apiserver/docs/source/api.rst @@ -93,6 +93,7 @@ Full User "photo_large": "uuid.jpg", "photo_medium": "uuid.jpg", "photo_small": "uuid.jpg", + "member_forms": "uuid.pdf", "set_details": true, "first_name": "Tanner", "last_name": "Collin", @@ -226,6 +227,7 @@ Member Details "photo_large": "uuid.jpg", "photo_medium": "uuid.jpg", "photo_small": "uuid.jpg", + "member_forms": "uuid.pdf", "set_details": true, "first_name": "Tanner", "last_name": "Collin", @@ -253,6 +255,7 @@ Member Details object to users when they claim their old member. :json photo\_\*: Should be served by nginx on the ``static`` subdomain. Refers 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 than one month: Prepaid, less than one month: Current, less than one month behind: Due, more than one month behind: Overdue. Members more @@ -273,6 +276,8 @@ Edit Member Details Set member details. + Member PDF forms will automatically be regenerated on any change. + **Users** Can only set certain fields of their own member. @@ -343,18 +348,6 @@ 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/webclient/src/Home.js b/webclient/src/Home.js index 8da43f3..718e235 100644 --- a/webclient/src/Home.js +++ b/webclient/src/Home.js @@ -44,6 +44,15 @@ function MemberInfo(props) { + {!member.photo_medium && + Welcome, new member! +

+ + Click here + to view your appliction forms. +

+
} + {!member.photo_medium && Please set a member photo!

Visit the account settings page to set one.

@@ -75,6 +84,12 @@ function MemberInfo(props) { + {member.photo_medium &&

+ + View application forms + +

} +
Latest Transactions