Added the ability to mass export activity attendance sheets

This commit is contained in:
Ceferino Patino 2022-12-12 19:58:22 -06:00
commit 76ef47caaf
7 changed files with 142 additions and 40 deletions

View file

@ -11,14 +11,13 @@ DEBUG = False
ALLOWED_HOSTS = [
'45.79.52.230',
'housewars.c4thebomb101.com',
'collegiate-housewars.herokuapp.com',
'collegiate-housewars.up.railway.app'
'csmb-housewars.herokuapp.com',
'*'
]
CSRF_TRUSTED_ORIGINS = [
'https://housewars.c4thebomb101.com',
'https://collegiate-housewars.herokuapp.com',
'https://collegiate-housewars.up.railway.app'
'https://csmb-housewars.herokuapp.com'
]
# Database
@ -35,4 +34,4 @@ DATABASES = {
}
}
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"

View file

@ -1,9 +1,14 @@
from django.http import HttpResponse
from django.contrib import admin, messages
from django.db.models import F
from django.utils.translation import ngettext
from housewars.utils import get_random_string
import io
import zipfile
from housewars.utils import get_random_string, load_pdf
from housewars.models import Activity, Award, Quota, UserEntry
from housewars.utils import load_pdf
class QuotaInline(admin.TabularInline):
@ -29,7 +34,7 @@ class ActivityAdmin(admin.ModelAdmin):
inlines = [QuotaInline, AwardsInline]
actions = ['generate_passwords']
actions = ['generate_passwords', 'export_a1_to_pdf', 'export_a2_to_pdf']
@admin.display(description='Hawk')
def hawk_signups(self, obj):
@ -57,12 +62,74 @@ class ActivityAdmin(admin.ModelAdmin):
@admin.action(description='Generate passwords for selected activities')
def generate_passwords(self, request, queryset):
for item in queryset:
item.password = get_random_string(8)
item.save()
for activity in queryset:
activity.password = get_random_string(8)
activity.save()
self.message_user(request, ngettext(
'Generated password for %d activity.',
'Generated passwords for %d activities.',
queryset.count(),
) % queryset.count(), messages.SUCCESS)
@admin.action(description='Export activity 1 attendance to pdf')
def export_a1_to_pdf(self, request, queryset):
file_list = {}
for activity in queryset:
user_entries = activity.activity1
# Augment the queryset with extra data
user_entries = user_entries.annotate(
a1_room=F('activity1__room_number')).annotate(a2_room=F('activity2__room_number'))
# Select headers that are to be unpacked
headers = ['first_name', 'last_name', 'grade', 'house',
'activity1', 'a1_room', 'activity2', 'a2_room']
file = load_pdf(user_entries, headers)
file_list[f"{activity.name} - 1"] = file
outfile = io.BytesIO()
with zipfile.ZipFile(outfile, 'w') as zf:
for name, file in file_list.items():
zf.writestr(f"{name}.pdf", file.getvalue())
outfile = outfile.getvalue()
response = HttpResponse(
outfile, content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename=activity1_attendance.zip'
return response
@admin.action(description='Export activity 2 attendance to pdf')
def export_a2_to_pdf(self, request, queryset):
file_list = {}
for activity in queryset:
user_entries = activity.activity2
# Augment the queryset with extra data
user_entries = user_entries.annotate(
a1_room=F('activity1__room_number')).annotate(a2_room=F('activity2__room_number'))
# Select headers that are to be unpacked
headers = ['first_name', 'last_name', 'grade', 'house',
'activity1', 'a1_room', 'activity2', 'a2_room']
file = load_pdf(user_entries, headers)
file_list[f"{activity.name} - 2"] = file
outfile = io.BytesIO()
with zipfile.ZipFile(outfile, 'w') as zf:
for name, file in file_list.items():
zf.writestr(f"{name}.pdf", file.getvalue())
outfile = outfile.getvalue()
response = HttpResponse(
outfile, content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename=activity2_attendance.zip'
return response

View file

@ -3,16 +3,10 @@ from django.db.models import F, Value
from django.db.models.functions import Concat
from django.http import HttpResponse, FileResponse
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import cm
from reportlab.platypus import Table, TableStyle, SimpleDocTemplate
from reportlab.lib.colors import black
import csv
import io
from housewars.models import UserEntry
from housewars.utils import unpack_values
from housewars.utils import unpack_values, load_pdf
class MentorListFilter(admin.SimpleListFilter):
@ -97,30 +91,13 @@ class UserEntryAdmin(admin.ModelAdmin):
def export_to_pdf(self, request, queryset):
# Augment the querset with extra data
queryset = queryset.annotate(
a1_room=F('activity1__room_number')).annotate(a2_room=F('activity1__room_number'))
# Initialize pdf object
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=letter)
elements = []
a1_room=F('activity1__room_number')).annotate(a2_room=F('activity2__room_number'))
# Select headers that are to be unpacked
headers = ['first_name', 'last_name', 'grade', 'house',
'activity1', 'a1_room', 'activity2', 'a2_room']
# Unpack queryset data
data = unpack_values(queryset, headers)
file = load_pdf(queryset, headers)
# Load data into table and set styles
table = Table(data, repeatRows=1)
table.setStyle(TableStyle(
[('INNERGRID', (0, 0), (-1, -1), 0.25, black), ('BOX', (0, 0), (-1, -1), 0.25, black)]))
# Load table into PDF file
elements.append(table)
# Build document
doc.build(elements)
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='download.pdf')
return FileResponse(file, as_attachment=True, filename='export.pdf')

View file

@ -0,0 +1,21 @@
from django.test import TestCase
import io
from housewars.utils import load_pdf
from housewars.models import House
class UnpackValuesTest(TestCase):
def setUp(self):
House.objects.create(name="Hawk")
House.objects.create(name="Snowy")
self.test_queryset = House.objects.all()
def test_matching_object_instance(self):
"""Correctly unpacks the headers into the first index"""
headers = [field.name for field in House._meta.fields]
self.assertIsInstance(
load_pdf(self.test_queryset, headers), io.BytesIO)

View file

@ -1,2 +1,3 @@
from .get_random_string import get_random_string
from .unpack_values import unpack_values
from .load_pdf import load_pdf

View file

@ -0,0 +1,38 @@
from reportlab.platypus import Table, TableStyle, SimpleDocTemplate
from reportlab.lib.pagesizes import letter
from reportlab.lib.colors import black
import io
from housewars.utils import unpack_values
def load_pdf(data, headers):
"""Loads data from queryset into a pdf file
:param queryset: The queryset that will be unpacked
:param headers: A list of the desired headers of the queryset
:returns A bytestream of a pdf file
"""
# Initialize pdf object
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=letter)
elements = []
# Unpack queryset data
data = unpack_values(data, headers)
# Load data into table and set styles
table = Table(data, repeatRows=1)
table.setStyle(TableStyle(
[('INNERGRID', (0, 0), (-1, -1), 0.25, black), ('BOX', (0, 0), (-1, -1), 0.25, black)]))
# Load table into PDF file
elements.append(table)
# Build document
doc.build(elements)
buffer.seek(0)
return buffer

View file

@ -1,4 +1,3 @@
import string
from django.db.models import QuerySet
from typing import List
@ -7,8 +6,8 @@ def unpack_values(queryset: QuerySet, headers: List[str]) -> List[List]:
"""Unpacks a queryset into a 2D array
:param queryset: The queryset that will be unpacked
:param headers: The headers of the
:returns A table headers, then rows
:param headers: A list of the desired headers of the queryset
:returns A 2D array of headers, then rows
"""
data = []