add endpoint of download examination schedule pdf file
This commit is contained in:
parent
03ffd355ed
commit
c71531ca10
@ -5,7 +5,8 @@ ENV PYTHONUNBUFFERED 1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt update && pip install --upgrade pip
|
||||
RUN apt update && \
|
||||
pip install --upgrade pip
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort
|
||||
import datetime
|
||||
|
||||
from apiflask import APIBlueprint
|
||||
from flask import abort, Response, make_response
|
||||
|
||||
from ...base.utils import paginate_models
|
||||
from ...dependencies import db
|
||||
from ...examination_schedule.models import ExaminationSchedule, Enrollment
|
||||
from ...students.models import Group
|
||||
from ...project_supervisor.models import ProjectSupervisor
|
||||
from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, MessageSchema, \
|
||||
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
||||
from ...examination_schedule.models import ExaminationSchedule
|
||||
from ...dependencies import db
|
||||
from ...base.utils import paginate_models
|
||||
from ..utils import generate_examination_schedule_pdf_file
|
||||
|
||||
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
||||
|
||||
@ -71,3 +76,33 @@ def set_date_of_examination_schedule(id: int, data: dict) -> dict:
|
||||
examination_schedule_query.update(data)
|
||||
db.session.commit()
|
||||
return {"message": "You set date of examination schedule!"}
|
||||
|
||||
|
||||
@bp.post('/<int:examination_schedule_id>/download/')
|
||||
def download_examination_schedule(examination_schedule_id: int) -> Response:
|
||||
examination_schedule = db.session.query(ExaminationSchedule). \
|
||||
filter(ExaminationSchedule.id == examination_schedule_id).first()
|
||||
|
||||
if examination_schedule is None:
|
||||
abort(404, "Examination schedule doesn't exist!")
|
||||
|
||||
distinct_dates = db.session.query(db.func.Date(Enrollment.start_date)).distinct().all()
|
||||
# print(distinct_dates)
|
||||
nested_enrollments = []
|
||||
for d in distinct_dates:
|
||||
date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date()
|
||||
enrollment = db.session.query(Enrollment).join(ExaminationSchedule, isouter=True).\
|
||||
join(Group, isouter=True).join(ProjectSupervisor, isouter=True). \
|
||||
filter(ExaminationSchedule.id == examination_schedule_id).filter(
|
||||
db.func.Date(Enrollment.start_date) == date_tmp).all()
|
||||
nested_enrollments.append(enrollment)
|
||||
|
||||
# print(nested_enrollments)
|
||||
pdf = generate_examination_schedule_pdf_file(examination_schedule.title, nested_enrollments)
|
||||
title = examination_schedule.title.replace("-", "_").split()
|
||||
filename = "_".join(title)
|
||||
|
||||
response = make_response(pdf)
|
||||
response.headers['Content-Type'] = 'application/pdf'
|
||||
response.headers['Content-Disposition'] = 'attachment; filename=%s.pdf' % filename
|
||||
return response
|
||||
|
@ -1,10 +1,19 @@
|
||||
from typing import Generator, Any, List
|
||||
import datetime
|
||||
from collections import defaultdict
|
||||
from io import BytesIO
|
||||
from itertools import chain
|
||||
from typing import Generator, Any, List
|
||||
|
||||
import pandas as pd
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.enums import TA_CENTER
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.lib.units import mm, inch
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Table
|
||||
|
||||
from .exceptions import InvalidNameOrTypeHeaderException
|
||||
from ..students.models import Student
|
||||
from ..examination_schedule.models import Enrollment
|
||||
|
||||
|
||||
def check_columns(df: pd.DataFrame) -> bool:
|
||||
@ -55,3 +64,82 @@ def generate_csv(students: List[Student]) -> str:
|
||||
|
||||
df = pd.DataFrame(dataframe)
|
||||
return df.to_csv(index=False)
|
||||
|
||||
|
||||
def generate_examination_schedule_pdf_file(title: str, nested_enrollments: List[List[Enrollment]]) -> bytes:
|
||||
pagesize = (297 * mm, 210 * mm)
|
||||
headers = ["lp.", "Godzina", "Nazwa projektu", "Opiekun", "Zespol", "Komisja"]
|
||||
pdf_buffer = BytesIO()
|
||||
my_doc = SimpleDocTemplate(
|
||||
pdf_buffer,
|
||||
pagesize=pagesize,
|
||||
topMargin=1 * inch,
|
||||
leftMargin=1 * inch,
|
||||
rightMargin=1 * inch,
|
||||
bottomMargin=1 * inch,
|
||||
title=title
|
||||
)
|
||||
|
||||
style = getSampleStyleSheet()
|
||||
bodyText = style['BodyText']
|
||||
bodyText.fontName = 'Helvetica'
|
||||
normal = style["Heading1"]
|
||||
normal.alignment = TA_CENTER
|
||||
flowables = []
|
||||
|
||||
# print(nested_enrollments)
|
||||
for enrollments in nested_enrollments:
|
||||
if len(enrollments) == 0:
|
||||
continue
|
||||
date = datetime.datetime.strftime(enrollments[0].start_date, '%d/%m/%Y')
|
||||
paragraph_1 = Paragraph(f"{title} ~ {date}", normal)
|
||||
flowables.append(paragraph_1)
|
||||
data = [headers]
|
||||
|
||||
for idx, e in enumerate(enrollments, start=1):
|
||||
new_date = e.start_date + datetime.timedelta(hours=2)
|
||||
group_name = e.group.name if e.group is not None else ""
|
||||
if group_name != '':
|
||||
ps = e.group.project_supervisor
|
||||
project_supervisor_fullname = f"{ps.first_name[0]}. {ps.last_name}"
|
||||
students = e.group.students
|
||||
# print(students)
|
||||
team = ", ".join([f"{s.first_name} {s.last_name}" for s in students])
|
||||
else:
|
||||
project_supervisor_fullname = ""
|
||||
team = ""
|
||||
|
||||
members = e.committee.members
|
||||
# print(members)
|
||||
if len(members) == 0:
|
||||
committee = ''
|
||||
else:
|
||||
members_iter = (f"{m.first_name[0]} {m.last_name}" for m in members)
|
||||
if project_supervisor_fullname != '':
|
||||
members_iter = chain(members_iter, [project_supervisor_fullname])
|
||||
|
||||
committee = ", ".join(members_iter)
|
||||
|
||||
data.append([str(idx), new_date.strftime("%H:%M"),
|
||||
Paragraph(group_name, bodyText),
|
||||
Paragraph(project_supervisor_fullname, bodyText),
|
||||
Paragraph(team, bodyText),
|
||||
Paragraph(committee, bodyText),
|
||||
])
|
||||
# print(data)
|
||||
|
||||
table = Table(data=data,
|
||||
style=[
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#A6F1A6")),
|
||||
('BACKGROUND', (0, 0), (1, -1), colors.HexColor("#A6F1A6"))
|
||||
],
|
||||
colWidths=[0.25 * inch, 0.7 * inch, 1.6 * inch, 1.5 * inch, 4 * inch, 3 * inch]
|
||||
)
|
||||
flowables.append(table)
|
||||
flowables.append(PageBreak())
|
||||
|
||||
my_doc.build(flowables)
|
||||
pdf_value = pdf_buffer.getvalue()
|
||||
pdf_buffer.close()
|
||||
return pdf_value
|
||||
|
@ -20,6 +20,7 @@ class Enrollment(Base):
|
||||
examination_schedule = db.relationship('ExaminationSchedule', backref='enrollments')
|
||||
committee = db.relationship("Committee", uselist=False, backref=db.backref('enrollment', passive_deletes=True))
|
||||
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
|
||||
group = db.relationship("Group", uselist=False, backref='enrollment')
|
||||
|
||||
|
||||
class Committee(Base):
|
||||
|
@ -17,7 +17,7 @@ class Group(Base):
|
||||
project_supervisor = db.relationship('ProjectSupervisor', backref='groups', lazy=True)
|
||||
points_for_first_term = db.Column(db.Integer, default=0, nullable=False)
|
||||
points_for_second_term = db.Column(db.Integer, default=0, nullable=False)
|
||||
enrollment = db.relationship('Enrollment', uselist=False, backref='group')
|
||||
# enrollment = db.relationship('Enrollment', uselist=False, backref='group')
|
||||
|
||||
@classmethod
|
||||
def search_by_name(cls, search_name: str = None) -> BaseQuery:
|
||||
|
@ -1,15 +1,15 @@
|
||||
alembic==1.7.7
|
||||
click==8.1.3
|
||||
Flask==2.1.2
|
||||
Flask-Cors==3.0.10
|
||||
flask-marshmallow==0.14.0
|
||||
Flask-Migrate==3.1.0
|
||||
Flask-SQLAlchemy==2.5.1
|
||||
MarkupSafe==2.1.1
|
||||
marshmallow-sqlalchemy==0.28.0
|
||||
pandas==1.4.2
|
||||
pytest==7.1.2
|
||||
pytest-flask==1.2.0
|
||||
click>=8.1.3,<8.2.0
|
||||
Flask>=2.1.2,<2.2.0
|
||||
Flask-Cors>=3.0.10,<3.1.0
|
||||
flask-marshmallow>=0.14.0,<0.15.0
|
||||
Flask-Migrate>=3.1.0,<3.2.0
|
||||
Flask-SQLAlchemy>=2.5.1,<2.6.0
|
||||
MarkupSafe>=2.1.1,<2.2.0
|
||||
marshmallow-sqlalchemy>=0.28.0,<0.29.0
|
||||
pandas>=1.4.2,<1.5.0
|
||||
pytest>=7.1.2,<7.2.0
|
||||
pytest-flask>=1.2.0,<1.3.0
|
||||
apiflask>=1.0.2,<1.1.0
|
||||
python-dotenv==0.21.0
|
||||
factory_boy==3.2.1
|
||||
factory_boy>=3.2.1,<3.3.0
|
||||
reportlab>=3.6.12,<3.7.0
|
||||
|
Loading…
Reference in New Issue
Block a user