diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue index 857cdac09725c6e7b86885ccae5513e644e563bf..8f048056c30adbaf24b8ed14393d2eb61dccdff5 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue +++ b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookPrintDialog.vue @@ -6,15 +6,13 @@ import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.v </script> <template> - <mobile-fullscreen-dialog - v-model="dialog" - > + <mobile-fullscreen-dialog v-model="dialog"> <template #activator> <secondary-action-button i18n-key="alsijil.coursebook.print.button" icon-text="$print" :loading="loading" - @click="dialog=true" + @click="dialog = true" :disabled="dialog" /> </template> @@ -50,7 +48,9 @@ import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.v /> <v-checkbox v-model="includeTeachersAndSubjectsTable" - :label="$t('alsijil.coursebook.print.include_teachers_and_subjects_table')" + :label=" + $t('alsijil.coursebook.print.include_teachers_and_subjects_table') + " /> <v-checkbox v-model="includePersonOverviews" @@ -64,9 +64,7 @@ import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.v </template> <template #actions> <!-- TODO: Should cancel reset state? --> - <cancel-button - @click="dialog=false" - /> + <cancel-button @click="dialog = false" /> <primary-action-button i18n-key="alsijil.coursebook.print.button" icon-text="$print" @@ -132,7 +130,7 @@ export default { methods: { setGroupSelection(groups) { this.$emit("input", groups); - this.currentGroupSelection=groups; + this.currentGroupSelection = groups; }, print() { this.$router.push({ @@ -140,7 +138,7 @@ export default { params: { groupIds: this.selectedGroups, }, - query: { + query: { cover: this.includeCover, abbreviations: this.includeAbbreviations, members_table: this.includeMembersTable, diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py index 4ad59b387532598ac392795a143e2acf90717fdb..efb06db7a0b298c21fa81663a2865a976b65cf77 100644 --- a/aleksis/apps/alsijil/model_extensions.py +++ b/aleksis/apps/alsijil/model_extensions.py @@ -93,11 +93,10 @@ def annotate_person_statistics( return persons -def annotate_person_statistics_from_documentations( - persons: QuerySet[Person], - docs: QuerySet[Documentation] +def annotate_person_statistics_from_documentations( + persons: QuerySet[Person], docs: QuerySet[Documentation] ) -> QuerySet[Person]: - """Annotate a queryset of persons with class register statistics from queryset of documentations.""" + """Annotate a queryset of persons with class register statistics from documentations.""" docs = list(docs.values_list("pk", flat=True)) return annotate_person_statistics( persons, diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py index 91fe27f044fb99587b77da89aaad954e96ddd29e..e622c5c3d47cadfe556e6a63387919b122661153 100644 --- a/aleksis/apps/alsijil/models.py +++ b/aleksis/apps/alsijil/models.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Optional, List +from typing import List, Optional from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied diff --git a/aleksis/apps/alsijil/tasks.py b/aleksis/apps/alsijil/tasks.py index 8b59c67e9508d3c1a01e4744af4ca119a121703c..365d407499fcdcc4a72c0ec8c583f0e37312bbdb 100644 --- a/aleksis/apps/alsijil/tasks.py +++ b/aleksis/apps/alsijil/tasks.py @@ -1,57 +1,59 @@ -from typing import Optional, List +from datetime import date +from typing import List, Optional -from copy import deepcopy -from datetime import date, timedelta - -from django.db.models import Q, Prefetch +from django.db.models import Prefetch, Q from django.utils.translation import gettext as _ -from calendarweek import CalendarWeek from celery.result import allow_join_result from celery.states import SUCCESS +from aleksis.apps.cursus.models import Course +from aleksis.apps.kolego.models.absence import AbsenceReason from aleksis.core.models import Group, PDFFile from aleksis.core.util.celery_progress import ProgressRecorder, recorded_task from aleksis.core.util.pdf import generate_pdf_from_template -from aleksis.apps.cursus.models import Course -from aleksis.apps.kolego.models.absence import AbsenceReason - -from .models import ExtraMark, NewPersonalNote, Documentation, ParticipationStatus from .model_extensions import annotate_person_statistics_from_documentations +from .models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus @recorded_task def generate_full_register_printout( - groups: List[int], - file_object: int, - recorder: ProgressRecorder, - include_cover: Optional[bool] = True, - include_abbreviations: Optional[bool] = True, - include_members_table: Optional[bool] = True, - include_teachers_and_subjects_table: Optional[bool] = True, - include_person_overviews: Optional[bool] = True, - include_coursebook: Optional[bool] = True + groups: List[int], + file_object: int, + recorder: ProgressRecorder, + include_cover: Optional[bool] = True, + include_abbreviations: Optional[bool] = True, + include_members_table: Optional[bool] = True, + include_teachers_and_subjects_table: Optional[bool] = True, + include_person_overviews: Optional[bool] = True, + include_coursebook: Optional[bool] = True, ): """Generate a configurable register printout as PDF for a group.""" - def prefetch_notable_participations(select_related=[], prefetch_related=[]): + + def prefetch_notable_participations(select_related=None, prefetch_related=None): + if not select_related: + select_related = [] + if not prefetch_related: + prefetch_related = [] return Prefetch( "participations", to_attr="notable_participations", - queryset=ParticipationStatus.objects - .filter(Q(absence_reason__tags__short_name="class_register") - | Q(tardiness__isnull=False) - ) + queryset=ParticipationStatus.objects.filter( + Q(absence_reason__tags__short_name="class_register") | Q(tardiness__isnull=False) + ) .select_related("absence_reason", *select_related) .prefetch_related(*prefetch_related), ) - def prefetch_personal_notes(name, select_related=[], prefetch_related=[]): + def prefetch_personal_notes(name, select_related=None, prefetch_related=None): + if not select_related: + select_related = [] + if not prefetch_related: + prefetch_related = [] return Prefetch( name, - queryset=NewPersonalNote.objects - .filter(Q(note__gt="") - | Q(extra_mark__isnull=False)) + queryset=NewPersonalNote.objects.filter(Q(note__gt="") | Q(extra_mark__isnull=False)) .select_related("extra_mark", *select_related) .prefetch_related(*prefetch_related), ) @@ -70,15 +72,19 @@ def generate_full_register_printout( _number_of_steps = 5 + len(groups) recorder.set_progress(1, _number_of_steps, _("Loading data ...")) - + groups = Group.objects.filter(pk__in=groups).order_by("name") if include_cover: groups = groups.select_related("school_term") if include_abbreviations or include_members_table: - context["absence_reasons"] = AbsenceReason.objects.filter(tags__short_name="class_register", count_as_absent=True) - context["absence_reasons_not_counted"] = AbsenceReason.objects.filter(tags__short_name="class_register", count_as_absent=False) + context["absence_reasons"] = AbsenceReason.objects.filter( + tags__short_name="class_register", count_as_absent=True + ) + context["absence_reasons_not_counted"] = AbsenceReason.objects.filter( + tags__short_name="class_register", count_as_absent=False + ) context["extra_marks"] = ExtraMark.objects.all() if include_members_table or include_person_overviews: @@ -96,45 +102,39 @@ def generate_full_register_printout( recorder.set_progress(2, _number_of_steps, _("Loading groups ...")) for i, group in enumerate(groups, start=1): - - recorder.set_progress(2 + i, _number_of_steps, _(f"Loading group {group.short_name or group.name} ...")) + recorder.set_progress( + 2 + i, _number_of_steps, _(f"Loading group {group.short_name or group.name} ...") + ) if include_members_table or include_person_overviews or include_coursebook: documentations = Documentation.objects.filter( Q(datetime_start__date__gte=group.school_term.date_start) & Q(datetime_end__date__lte=group.school_term.date_end) - & Q(pk__in=Documentation.objects.filter(course__groups=group) + & Q( + pk__in=Documentation.objects.filter(course__groups=group) .values_list("pk", flat=True) .union( - Documentation.objects.filter(course__groups__parent_groups=group).values_list( - "pk", flat=True - ) - ) + Documentation.objects.filter( + course__groups__parent_groups=group + ).values_list("pk", flat=True) ) + ) ) if include_members_table or include_person_overviews: - group.members_with_stats = annotate_person_statistics_from_documentations(group.members.all(), documentations) + group.members_with_stats = annotate_person_statistics_from_documentations( + group.members.all(), documentations + ) if include_person_overviews: doc_query_set = documentations.select_related("subject").prefetch_related("teachers") group.members_with_stats = group.members_with_stats.prefetch_related( prefetch_notable_participations( - prefetch_related=[ - Prefetch( - "related_documentation", - queryset=doc_query_set - ) - ] + prefetch_related=[Prefetch("related_documentation", queryset=doc_query_set)] ), prefetch_personal_notes( "new_personal_notes", - prefetch_related=[ - Prefetch( - "documentation", - queryset=doc_query_set - ) - ] + prefetch_related=[Prefetch("documentation", queryset=doc_query_set)], ), ) @@ -142,20 +142,20 @@ def generate_full_register_printout( group.as_list = [group] if include_coursebook: - group.documentations_by_day = {} - documentations = documentations.order_by("datetime_start").prefetch_related( + group.documentations_by_day = documentations.order_by( + "datetime_start" + ).prefetch_related( prefetch_notable_participations(select_related=["person"]), - prefetch_personal_notes("personal_notes", select_related=["person"]) + prefetch_personal_notes("personal_notes", select_related=["person"]), ) - for doc in documentations: - group.documentations_by_day.setdefault(doc.datetime_start.date(), []).append(doc) - context["groups"] = groups recorder.set_progress(3 + len(groups), _number_of_steps, _("Generating template ...")) file_object, result = generate_pdf_from_template( - "alsijil/print/register_for_group.html", context, file_object=PDFFile.objects.get(pk=file_object) + "alsijil/print/register_for_group.html", + context, + file_object=PDFFile.objects.get(pk=file_object), ) recorder.set_progress(4 + len(groups), _number_of_steps, _("Generating PDF ...")) diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/absences.html b/aleksis/apps/alsijil/templates/alsijil/partials/absences.html deleted file mode 100644 index d1faaadd474111453bc07e608ddb63aee11efedc..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/absences.html +++ /dev/null @@ -1,9 +0,0 @@ -{% load i18n rules %} -{% for note in notes %} - {% has_perm "alsijil.view_personalnote_rule" user note as can_view_personalnote %} - {% if can_view_personalnote %} - <span class="{% if note.excused %}green-text{% else %}red-text{% endif %}">{{ note.person }} - {% if note.excused %}{% if note.excuse_type %}({{ note.excuse_type.short_name }}){% else %}{% trans "(e)" %}{% endif %}{% else %}{% trans "(u)" %}{% endif %}{% if not forloop.last %},{% endif %} - </span> - {% endif %} -{% endfor %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/legend.html b/aleksis/apps/alsijil/templates/alsijil/partials/legend.html deleted file mode 100644 index bf0c82d792b57943b36502f0b94dff3db193a70d..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/legend.html +++ /dev/null @@ -1,71 +0,0 @@ -{% load i18n %} -<div class="card"> - <div class="card-content"> - <div class="card-title">{% trans "Legend" %}</div> - <div class="row"> - <div class="col s12 m12 l4"> - <h6>{% trans "General" %}</h6> - <ul class="collection"> - <li class="collection-item chip-height"> - <strong>{% trans "(a)" %}</strong> {% trans "Absences" %} - <span class="chip secondary-color white-text right">0</span> - </li> - <li class="collection-item chip-height"> - <strong>{% trans "(u)" %}</strong> {% trans "Unexcused absences" %} - <span class="chip red white-text right">0</span> - </li> - <li class="collection-item chip-height"> - <strong>{% trans "Sum (e)" %}</strong> {% trans "Sum of excused absences" %} - <span class="chip green white-text right">0</span> - </li> - <li class="collection-item chip-height"> - <strong>{% trans "(e)" %}</strong> {% trans "Regular excused absences" %} - <span class="chip grey white-text right">0</span> - </li> - </ul> - </div> - - {% if excuse_types %} - <div class="col s12 m12 l4"> - <h6>{% trans "Excuse types" %}</h6> - - <ul class="collection"> - {% for excuse_type in excuse_types %} - <li class="collection-item chip-height"> - <strong>({{ excuse_type.short_name }})</strong> {{ excuse_type.name }} - <span class="chip grey white-text right">0</span> - </li> - {% endfor %} - </ul> - {% if excuse_types_not_absent %} - <h6>{% trans "Excuse types (not counted as absent)" %}</h6> - - <ul class="collection"> - {% for excuse_type in excuse_types_not_absent %} - <li class="collection-item chip-height"> - <strong>({{ excuse_type.short_name }})</strong> {{ excuse_type.name }} - <span class="chip grey white-text right">0</span> - </li> - {% endfor %} - </ul> - {% endif %} - </div> - {% endif %} - - {% if extra_marks %} - <div class="col s12 m12 l4"> - <h6>{% trans "Extra marks" %}</h6> - - <ul class="collection"> - {% for extra_mark in extra_marks %} - <li class="collection-item chip-height"> - <strong>{{ extra_mark.short_name }}</strong> {{ extra_mark.name }} - <span class="chip grey white-text right">0</span> - </li> - {% endfor %} - </ul> - </div> - {% endif %} - </div> - </div> -</div> diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html deleted file mode 100644 index acd8d283d6ecc9fe7ed84234600444e1424a0e49..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html +++ /dev/null @@ -1,36 +0,0 @@ -{% load i18n week_helpers %} - -{% now_datetime as now_dt %} - -{% if has_documentation or register_object.has_documentation %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Data complete") icon="mdi:check-circle-outline" color="green" %} -{% elif not register_object.period %} - {% if week %} - {% period_to_time_start week register_object.raw_period_from_on_day as time_start %} - {% period_to_time_end week register_object.raw_period_to_on_day as time_end %} - {% else %} - {% period_to_time_start register_object.date_start register_object.period_from as time_start %} - {% period_to_time_end register_object.date_end register_object.period_to as time_end %} - {% endif %} - - {% if now_dt > time_end %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="mdi:alert-outline" color="red" %} - {% elif now_dt > time_start and now_dt < time_end %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="mdi:dots-horizontal" color="orange" %} - {% else %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Event") icon="mdi:calendar" color="purple" %} - {% endif %} -{% else %} - {% period_to_time_start week register_object.period as time_start %} - {% period_to_time_end week register_object.period as time_end %} - - {% if substitution.cancelled or register_object.get_substitution.cancelled %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Lesson cancelled") icon="mdi:close" color="red" %} - {% elif now_dt > time_end %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="mdi:alert-outline" color="red" %} - {% elif now_dt > time_start and now_dt < time_end %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="mdi:dots-horizontal" color="orange" %} - {% elif substitution or register_object.get_substitution %} - {% include "alsijil/partials/lesson_status_icon.html" with text=_("Substitution") icon="mdi:update" color="orange" %} - {% endif %} -{% endif %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html deleted file mode 100644 index 2c016c685bb89e8edca9e75408fd11109f655e0b..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html +++ /dev/null @@ -1,12 +0,0 @@ -{% if chip %} - <span class="{% if chip %}chip{% endif %} {{ color }} white-text {{ css_class }}"> - <i class="material-icons iconify left" data-icon="{{ icon }}"></i> - {{ text }} - </span> -{% else %} - <i class="material-icons iconify {{ color }}{% firstof color_suffix "-text" %} tooltipped {{ css_class }}" - data-icon="{{ icon }}" - data-position="bottom" - data-tooltip="{{ text }}" title="{{ text }}"> - </i> -{% endif %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html b/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html deleted file mode 100644 index e2053816e4a682b5de56596f0cf998e2b4e0a371..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html +++ /dev/null @@ -1,43 +0,0 @@ -{% load i18n material_form django_tables2 %} -<div class="card"> - <div class="card-content"> - <div class="card-title">{% trans "Lesson filter" %}</div> - <form action="" method="get"> - {% form form=filter_form %}{% endform %} - <button type="submit" class="btn waves-effect waves-light"> - <i class="material-icons iconify left" data-icon="mdi:refresh"></i> - {% trans "Update filters" %} - </button> - </form> - </div> -</div> - -{% if table %} - <div class="card"> - <div class="card-content"> - <form action="" method="post"> - {% csrf_token %} - <div class="row"> - <div class="col s12 {% if action_form %}m4 l4 xl6{% endif %}"> - <div class="card-title">{% trans "Lesson table" %}</div> - </div> - {% if action_form %} - <div class="col s12 m8 l8 xl6"> - <div class="col s12 m8"> - {% form form=action_form %}{% endform %} - </div> - <div class="col s12 m4"> - <button type="submit" class="btn waves-effect waves-primary"> - {% trans "Execute" %} - <i class="material-icons iconify right" data-icon="mdi:send-outline"></i> - </button> - </div> - </div> - {% endif %} - </div> - {% render_table table %} - - </form> - </div> - </div> -{% endif %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html b/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html index 3418b1c40e4bfabf9f11c5cc9074efbe23fb73c8..fa2fb386a1e69e4734f448606fc24eebe8ac9d84 100644 --- a/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html +++ b/aleksis/apps/alsijil/templates/alsijil/partials/person_overview.html @@ -1,15 +1,15 @@ {% load static i18n data_helpers %} -<h4>{% blocktrans %}Personal Overview: {{ person.last_name }}, {{ person.first_name }}{% endblocktrans %}</h4> +<h4>{% blocktrans with full_name=person.full_name %}Personal Overview: {{ person.full_name }}{% endblocktrans %}</h4> <h5>{% blocktrans %}Contact Details{% endblocktrans %}</h5> <table class="person-info"> <tr> <td rowspan="6" class="person-img"> {% if person.photo %} - <img src="{{ person.photo.url }}" alt="{{ person.first_name }} {{ person.last_name }}"/> + <img src="{{ person.photo.url }}" alt="{{ person.full_name }}"/> {% else %} - <img src="{% static 'img/fallback.png' %}" alt="{{ person.first_name }} {{ person.last_name }}"/> + <img src="{% static 'img/fallback.png' %}" alt="{{ person.full_name }}"/> {% endif %} </td> <td><i class="material-icons iconify" data-icon="mdi:account-outline"></i></td> diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html b/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html deleted file mode 100644 index 69ce9c6c9a011744eb2b3bed80228fe3147ff01b..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html +++ /dev/null @@ -1,147 +0,0 @@ -{% load data_helpers time_helpers i18n rules %} - -{% if not persons %} - <figure class="alert primary"> - <i class="material-icons iconify left" data-icon="mdi:alert-outline"></i> - {% blocktrans %}No students available.{% endblocktrans %} - </figure> -{% else %} - <table class="highlight responsive-table"> - <thead> - <tr class="hide-on-med-and-down"> - <th rowspan="2">{% trans "Name" %}</th> - <th rowspan="2">{% trans "Primary group" %}</th> - <th colspan="{{ excuse_types.count|add:4 }}">{% trans "Absences" %}</th> - {% if excuse_types_not_absent %} - <th colspan="{{ excuse_types_not_absent.count }}">{% trans "Uncounted Absences" %}</th> - {% endif %} - {% if extra_marks %} - <th colspan="{{ extra_marks.count }}">{% trans "Extra marks" %}</th> - {% endif %} - <th rowspan="2">{% trans "Tardiness" %}</th> - <th rowspan="2"></th> - </tr> - <tr class="hide-on-large-only"> - <th class="truncate">{% trans "Name" %}</th> - <th class="truncate">{% trans "Primary group" %}</th> - <th class="truncate chip-height">{% trans "Absences" %}</th> - <th class="chip-height">{% trans "Sum (e)" %}</th> - <th class="chip-height">{% trans "(e)" %}</th> - {% for excuse_type in excuse_types %} - <th class="chip-height"> - ({{ excuse_type.short_name }}) - </th> - {% endfor %} - <th class="chip-height">{% trans "(u)" %}</th> - {% for excuse_type in excuse_types_not_absent %} - <th class="chip-height"> - ({{ excuse_type.short_name }}) - </th> - {% endfor %} - {% for extra_mark in extra_marks %} - <th class="chip-height"> - {{ extra_mark.short_name }} - </th> - {% endfor %} - <th class="truncate chip-height">{% trans "Tardiness" %}</th> - <th rowspan="2"></th> - </tr> - <tr class="hide-on-med-and-down"> - <th>{% trans "Sum" %}</th> - <th>{% trans "Sum (e)" %}</th> - <th>{% trans "(e)" %}</th> - {% for excuse_type in excuse_types %} - <th> - ({{ excuse_type.short_name }}) - </th> - {% endfor %} - <th>{% trans "(u)" %}</th> - {% for excuse_type in excuse_types_not_absent %} - <th> - ({{ excuse_type.short_name }}) - </th> - {% endfor %} - {% for extra_mark in extra_marks %} - <th> - {{ extra_mark.short_name }} - </th> - {% endfor %} - </tr> - </thead> - {% for person in persons %} - <tr> - <td> - <a href="{% url "overview_person" person.pk %}"> - {{ person }} - </a> - </td> - <td> - {% firstof person.primary_group "–" %} - </td> - <td> - <span class="chip secondary-color white-text" title="{% trans "Absences" %}"> - {{ person.absences_count }} - </span> - </td> - <td class="green-text"> - <span class="chip green white-text" title="{% trans "Excused" %}"> - {{ person.excused }} - </span> - </td> - <td> - <span class="chip grey white-text" title="{% trans "Regular excused" %}"> - {{ person.excused_without_excuse_type }} - </span> - </td> - {% for excuse_type in excuse_types %} - <td> - <span class="chip grey white-text" title="{{ excuse_type.name }}"> - {{ person|get_dict:excuse_type.count_label }} - </span> - </td> - {% endfor %} - <td class="red-text"> - <span class="chip red white-text" title="{% trans "Unexcused" %}"> - {{ person.unexcused }} - </span> - </td> - {% for excuse_type in excuse_types_not_absent %} - <td> - <span class="chip grey white-text" title="{{ excuse_type.name }}"> - {{ person|get_dict:excuse_type.count_label }} - </span> - </td> - {% endfor %} - {% for extra_mark in extra_marks %} - <td> - <span class="chip grey white-text" title="{{ extra_mark.name }}"> - {{ person|get_dict:extra_mark.count_label }} - </span> - </td> - {% endfor %} - <td> - <span class="chip orange white-text" title="{% trans "Tardiness" %}"> - {% firstof person.tardiness|to_time|time:"H\h i\m" "–" %} - </span> - <span class="chip orange white-text" title="{% trans "Count of tardiness" %}">{{ person.tardiness_count }} ×</span> - </td> - - <td> - <a class="btn primary waves-effect waves-light" href="{% url "overview_person" person.pk %}"> - <i class="material-icons iconify left" data-icon="mdi:chart-box-outline"></i> - <span class="hide-on-med-and-down"> {% trans "Show more details" %}</span> - <span class="hide-on-large-only">{% trans "Details" %}</span> - </a> - - {% has_perm "alsijil.register_absence_rule" user person as can_register_absence %} - {% if can_register_absence %} - <a class="btn primary-color waves-effect waves-light" href="{% url "register_absence" person.pk %}"> - <i class="material-icons iconify left" data-icon="mdi:message-draw"></i> - {% trans "Register absence" %} - </a> - {% endif %} - </td> - </tr> - {% endfor %} -{% endif %} -</table> diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html b/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html index eb18482185cd5614eca55b219c8a2302c8ceea59..01e05170dc38dd9168c4c73b97c293e6d6f3e0a1 100644 --- a/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html +++ b/aleksis/apps/alsijil/templates/alsijil/partials/register_coursebook.html @@ -15,24 +15,19 @@ </tr> </thead> <tbody> - {% for day, documentations in group.documentations_by_day.items %} - {% for doc in documentations %} - <tr class=" - {% if doc.amends %} - {% if doc.amends.cancelled %} - lesson-cancelled - {% endif %} - {% if doc.amends.amends %} - lesson-substituted - {% endif %} + {% for documentation in group.documentations_by_day %} + {% ifchanged documentation.datetime_start.date %} + <tr><th colspan="6">{{ documentation.datetime_start.date|date:"D" }}</th></tr> + {% endifchanged %} + <tr class=" + {% if doc.amends %} + {% if doc.amends.cancelled %} + lesson-cancelled {% endif %} {% if forloop.first %} lessons-day-first {% endif %} "> - {% if forloop.first %} - <th rowspan="{{ documentations|length }}">{{ day|date:"D" }}</th> - {% endif %} <td class="lesson-pe"> {% if doc.amends %} {% if doc.amends.slot_number_start == doc.amends.slot_number_end %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/tardinesses.html b/aleksis/apps/alsijil/templates/alsijil/partials/tardinesses.html deleted file mode 100644 index ca20a9c4d1f420736febd149e657a67e855d45f4..0000000000000000000000000000000000000000 --- a/aleksis/apps/alsijil/templates/alsijil/partials/tardinesses.html +++ /dev/null @@ -1,7 +0,0 @@ -{% load rules %} -{% for note in notes %} - {% has_perm "alsijil.view_personalnote_rule" user note as can_view_personalnote %} - {% if can_view_personalnote %} - <span>{{ note.person }} ({{ note.tardiness }}'){% if not forloop.last %},{% endif %}</span> - {% endif %} -{% endfor %} diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py index b03ac2cb3e4d63b581701466e1e541bc108ecd3d..8017db1c94d063930ed462be021846841bce3d40 100644 --- a/aleksis/apps/alsijil/urls.py +++ b/aleksis/apps/alsijil/urls.py @@ -3,11 +3,7 @@ from django.urls import path from . import views urlpatterns = [ - path( - "print/groups/<path:ids>/", - views.full_register_for_group, - name="full_register_for_group" - ), + path("print/groups/<path:ids>/", views.full_register_for_group, name="full_register_for_group"), path("group_roles/", views.GroupRoleListView.as_view(), name="group_roles"), path("group_roles/create/", views.GroupRoleCreateView.as_view(), name="create_group_role"), path( diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index df6a8c40e7ac5f9b1614888f71d08767c015d7aa..c48c13eea04af8ab0c205ba851717a936cfe50a6 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -1,20 +1,19 @@ -from typing import Any, Dict, Optional +from typing import Any, Dict +from django.core.exceptions import BadRequest, PermissionDenied from django.db.models import Q from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.decorators import method_decorator -from django.utils.http import url_has_allowed_host_and_scheme from django.utils.translation import gettext as _ from django.views.decorators.cache import never_cache from django.views.generic import DetailView -from django.core.exceptions import PermissionDenied from django_tables2 import SingleTableView from reversion.views import RevisionMixin -from rules.contrib.views import PermissionRequiredMixin, permission_required +from rules.contrib.views import PermissionRequiredMixin from aleksis.core.decorators import pwa_cache from aleksis.core.mixins import ( @@ -26,7 +25,7 @@ from aleksis.core.mixins import ( from aleksis.core.models import Group, PDFFile from aleksis.core.util import messages from aleksis.core.util.celery_progress import render_progress_page -from aleksis.core.util.core_helpers import has_person, objectgetter_optional +from aleksis.core.util.core_helpers import has_person from .forms import ( AssignGroupRoleForm, @@ -42,13 +41,15 @@ from .tasks import generate_full_register_printout def full_register_for_group(request: HttpRequest, ids: str) -> HttpResponse: """Show a configurable register printout as PDF for a group.""" + def parse_get_param(name): """Defaults to true""" - print(name) - print(request.GET.get(name)) - return not request.GET.get(name) == "false" + return request.GET.get(name) != "false" - ids = [int(id_) for id_ in ids.split("/")] + try: + ids = [int(id_) for id_ in ids.split("/")] + except ValueError as e: + raise BadRequest() from e groups = [] for id_ in ids: @@ -72,7 +73,7 @@ def full_register_for_group(request: HttpRequest, ids: str) -> HttpResponse: include_members_table=parse_get_param("members_table"), include_teachers_and_subjects_table=parse_get_param("teachers_and_subjects_table"), include_person_overviews=parse_get_param("person_overviews"), - include_coursebook=parse_get_param("coursebook") + include_coursebook=parse_get_param("coursebook"), ) back_url = request.GET.get("back", "") @@ -80,7 +81,9 @@ def full_register_for_group(request: HttpRequest, ids: str) -> HttpResponse: return render_progress_page( request, result, - title=_(f"Generate register printout for {', '.join([group.short_name for group in groups])}"), + title=_( + f"Generate register printout for {', '.join([group.short_name for group in groups])}" + ), progress_title=_("Generate register printout …"), success_message=_("The printout has been generated successfully."), error_message=_("There was a problem while generating the printout."),