Skip to content
Snippets Groups Projects
Verified Commit efbf13f3 authored by Lloyd Meins's avatar Lloyd Meins :thought_balloon: Committed by Jonathan Weth
Browse files

Export timetable as pdf

parent 08bf4821
No related branches found
No related tags found
1 merge request!77Resolve "PDF export for timetables"
......@@ -81,7 +81,7 @@ table.substitutions td, table.substitutions th {
}
.lesson-with-sub {
border: 3px solid red;
border: 3px solid #ff0000;
border-radius: 3px;
}
......
body {
font-family: sans-serif !important;
}
.timetable-plan .row, .timetable-plan .col {
display: flex;
padding: 0rem;
}
.timetable-plan .row {
margin-bottom: 0rem;
}
.lesson-card, .timetable-title-card {
margin: 0;
display: flex;
flex-grow: 1;
min-height: 40px;
box-shadow: none;
border: 1px solid black;
margin-right: -1px;
margin-top: -1px;
border-radius: 0px;
font-size: 11px;
}
.lesson-card .card-content > div {
padding: 1px;
}
.card .card-title {
font-size: 18px;
}
.timetable-title-card .card-content {
padding: 10px;
}
......@@ -37,7 +37,7 @@
</div>
{# Show print button only if not on mobile #}
<div class="col s4 m6 l4 xl3 right align-right no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right hide-on-small-and-down" id="print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right hide-on-small-and-down" href="{% url "timetable_print" type.value pk %}">
<i class="material-icons center">print</i>
</a>
</div>
......
{# -*- engine:django -*- #}
{% extends 'core/base.html' %}
{% extends 'core/base_print.html' %}
{% load data_helpers static i18n %}
{% block extra_head %}
<link rel="stylesheet" href="{% static 'css/chronos/timetable.css' %}">
<link rel="stylesheet" href="{% static 'css/chronos/timetable_print.css' %}">
{% endblock %}
{% block browser_title %}{% blocktrans %}Timetable{% endblocktrans %}{% endblock %}
{% block content %}
{% if smart %}
<script type="text/javascript" src="{% static "js/helper.js" %}"></script>
{{ week_select|json_script:"week_select" }}
<script type="text/javascript" src="{% static "js/chronos/week_select.js" %}"></script>
{% endif %}
<div class="row no-margin">
<div class="col s8 m6 l8 xl9">
<h4>
<h5>
{% trans "Timetable" %} <i>{{ el }}</i>
</h4>
</h5>
{# Show class teacher and deputy class teacher #}
{% if type.value == "group" and el.owners.all %}
<h5>{% trans "Group teachers:" %}
<p class="no-margin">{% trans "Group teachers:" %}
{% for teacher in el.owners.all %}
<span data-position="bottom" class="tooltipped"
data-tooltip="{{ teacher }}">
<a href="{% url "timetable" "teacher" teacher.pk %}">
{{ teacher.short_name }}</a></span>{% if not forloop.last %},{% endif %}
{{ teacher.short_name }}{% if not forloop.last %},{% endif %}
{% endfor %}
</h5>
</p>
{% endif %}
</div>
{# Show print button only if not on mobile #}
<div class="col s4 m6 l4 xl3 right align-right no-print">
<a class="waves-effect waves-teal btn-flat btn-flat-medium right hide-on-small-and-down" id="print">
<i class="material-icons center">print</i>
</a>
</div>
</div>
<div class="row">
{% if smart %}
{# Show if smart #}
{# Toggle button to regular and smart plan badge #}
<div class="row s12 m6 left">
<span class="badge new primary-color left smart-plan-badge">{% trans "SMART PLAN" %}</span>
<a class="waves-effect waves-light btn-flat no-print"
href="{% url "timetable_regular" type.value pk "regular" %}">
<i class="material-icons left">slideshow</i>
{% trans "Show regular timetable" %}
</a>
</div>
{# Week select #}
{% include "chronos/partials/week_select.html" with wanted_week=week %}
{% else %}
{# Show if regular #}
<a class="waves-effect waves-light btn-flat no-print"
href="{% url "timetable" type.value pk %}">
<i class="material-icons left">slideshow</i>
{% trans "Show SMART PLAN" %}
</a>
{% endif %}
</div>
{% include "core/partials/announcements.html" with announcements=announcements show_interval=1 %}
{# show full timetable on tablets, laptops and pcs #}
<div class="timetable-plan hide-on-small-and-down">
<div class="timetable-plan">
{# Week days #}
<div class="row">
......@@ -81,45 +32,19 @@
</div>
{# Show short weekdays on tablets #}
{% for weekday in weekdays_short %}
<div class="col s2 hide-on-large-only">
<div class="card timetable-title-card">
<div class="card-content">
<span class="card-title">
{{ weekday.name }}
</span>
{% if smart %}
{{ weekday.date }}
{% if weekday.holiday %}
<br/>{% include "chronos/partials/holiday.html" with holiday=weekday.holiday %}
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endfor %}
{# Show long weekdays elsewere #}
{% for weekday in weekdays %}
<div class="col s2 hide-on-med-only">
<div class="col s2">
<div class="card timetable-title-card">
<div class="card-content">
<span class="card-title">
{{ weekday.name }}
</span>
{% if smart %}
{{ weekday.date }}
{% if weekday.holiday %}
<br/>{% include "chronos/partials/holiday.html" with holiday=weekday.holiday %}
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{# Lessons #}
{% for row in timetable %}
{% for row in timetable %}
<div class="row">
<div class="col s2">
{% if row.type == "period" %}
......@@ -141,42 +66,4 @@
{% endfor %}
</div>
{# show 5 seperate ones on mobiles #}
<div class="timetable-plan hide-on-med-and-up">
{% for weekday in weekdays %}
<div class="card timetable-mobile-title-card">
<div class="card-content">
<span class="card-title">
{{ weekday.name }}
</span>
{% if smart %}
{{ weekday.date }}
{% if weekday.holiday %}
<br/>{% include "chronos/partials/holiday.html" with holiday=weekday.holiday %}
{% endif %}
{% endif %}
</div>
</div>
{% for row in timetable %}
<div class="row">
<div class="col s4">
{% include "chronos/partials/period_time.html" with period=row.period periods=periods %}
</div>
{% for col in row.cols %}
{% if forloop.counter0 == weekday.key %}
<div class="col s8">
{# A lesson #}
{% if row.type == "period" %}
{% include "chronos/partials/elements.html" with elements=col %}
{% else %}
{% include "chronos/partials/supervision.html" with supervision=col %}
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}
......@@ -10,25 +10,26 @@ urlpatterns = [
views.my_timetable,
name="my_timetable_by_date",
),
path("timetable/<str:type_>/<int:pk>/", views.timetable, name="timetable"),
path(
"timetable/<str:type_>/<int:pk>/<int:year>/<int:week>/",
"timetable/<str:type_>/<int:pk>/",
views.timetable,
name="timetable_by_week",
name="timetable",
),
path(
"timetable/<str:type_>/<int:pk>/<str:regular>/", views.timetable, name="timetable_regular",
"timetable/<str:type_>/<int:pk>/<int:year>/<int:week>/",
views.timetable,
name="timetable_by_week",
),
path("timetable/<str:type_>/<int:pk>/<str:print_plan>/", views.timetable, name="timetable_print"),
path(
"timetable/<str:type_>/<int:pk>/<int:year>/<int:week>/<str:print_plan>/",
"timetable/<str:type_>/<int:pk>/print/",
views.timetable,
name="timetable_by_week_print",
{"is_print": True},
name="timetable_print",
),
path(
"timetable/<str:type_>/<int:pk>/<str:regular>/<str:print_plan>/",
"timetable/<str:type_>/<int:pk>/<str:regular>/",
views.timetable,
name="timetable_regular_print",
name="timetable_regular",
),
path("lessons/", views.lessons_day, name="lessons_day"),
path(
......
......@@ -17,6 +17,8 @@ def get_el_by_pk(
week: Optional[int] = None,
regular: Optional[str] = None,
prefetch: bool = False,
*args,
**kwargs,
):
if type_ == TimetableType.GROUP.value:
return get_object_or_404(
......
import os
from datetime import datetime, timedelta
from typing import Optional
import subprocess
from tempfile import mkstemp
from django.db.models import Count, Q
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound, FileResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache
from django.template.loader import get_template, render_to_string
from django_tables2 import RequestConfig
from rules.contrib.views import permission_required
......@@ -24,6 +28,7 @@ from .util.build import build_substitutions_list, build_timetable, build_weekday
from .util.chronos_helpers import get_el_by_pk, get_substitution_by_id
from .util.date import CalendarWeek, get_weeks_for_year
from .util.js import date_unix
from aleksis.core.settings import STATIC_ROOT
@permission_required("chronos.view_timetable_overview")
......@@ -124,13 +129,16 @@ def timetable(
year: Optional[int] = None,
week: Optional[int] = None,
regular: Optional[str] = None,
print_plan: Optional[str] = None,
is_print: bool = False,
) -> HttpResponse:
"""View a selected timetable for a person, group or room."""
context = {}
is_smart = regular != "regular"
if is_print:
is_smart = False
el = get_el_by_pk(request, type_, pk, prefetch=True)
if type(el) == HttpResponseNotFound:
......@@ -186,9 +194,23 @@ def timetable(
"timetable_by_week", args=[type_.value, pk, week_next.year, week_next.week]
)
if print_plan == "print":
return render(request, "chronos/timetable_print.html", context)
return render(request, "chronos/timetable.html", context)
if is_print:
template_name = "chronos/timetable_print.html"
template = get_template(template_name)
html_template = render_to_string(template_name, context).replace("/static", STATIC_ROOT)
f, path = mkstemp(".html")
print(path)
with open(path, "w") as f:
f.write(html_template)
f2, path2 = mkstemp(".pdf")
subprocess.run(["electron-pdf", path, path2])
file = open(path2, "rb")
return FileResponse(file, content_type="application/pdf")
else:
template_name = "chronos/timetable.html"
return render(request, template_name, context)
@permission_required("chronos.view_lessons_day")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment