From 2b83a633529e0690df7f2ae668a1c98c95f5d59a Mon Sep 17 00:00:00 2001 From: Dominik George <nik@naturalnet.de> Date: Fri, 13 Dec 2019 14:16:23 +0100 Subject: [PATCH] [Reformat} Run isort and black --- biscuit/apps/alsijil/__init__.py | 6 +- biscuit/apps/alsijil/apps.py | 4 +- biscuit/apps/alsijil/forms.py | 71 ++-- biscuit/apps/alsijil/menus.py | 43 +-- .../apps/alsijil/migrations/0001_initial.py | 123 +++++-- .../0002_add_personal_note_filter.py | 59 +++- biscuit/apps/alsijil/model_extensions.py | 47 +-- biscuit/apps/alsijil/models.py | 57 ++- biscuit/apps/alsijil/tables.py | 8 +- biscuit/apps/alsijil/urls.py | 51 ++- biscuit/apps/alsijil/views.py | 328 +++++++++++------- 11 files changed, 528 insertions(+), 269 deletions(-) diff --git a/biscuit/apps/alsijil/__init__.py b/biscuit/apps/alsijil/__init__.py index 371cf243f..13d090787 100644 --- a/biscuit/apps/alsijil/__init__.py +++ b/biscuit/apps/alsijil/__init__.py @@ -1,8 +1,8 @@ import pkg_resources try: - __version__ = pkg_resources.get_distribution('BiscuIT-App-Alsijil').version + __version__ = pkg_resources.get_distribution("BiscuIT-App-Alsijil").version except Exception: - __version__ = 'unknown' + __version__ = "unknown" -default_app_config = 'biscuit.apps.alsijil.apps.AlsijilConfig' +default_app_config = "biscuit.apps.alsijil.apps.AlsijilConfig" diff --git a/biscuit/apps/alsijil/apps.py b/biscuit/apps/alsijil/apps.py index 23151cb6a..8fb3b07a4 100644 --- a/biscuit/apps/alsijil/apps.py +++ b/biscuit/apps/alsijil/apps.py @@ -2,5 +2,5 @@ from biscuit.core.util.apps import AppConfig class AlsijilConfig(AppConfig): - name = 'biscuit.apps.alsijil' - verbose_name = 'BiscuIT - Alsijil (Class register)' + name = "biscuit.apps.alsijil" + verbose_name = "BiscuIT - Alsijil (Class register)" diff --git a/biscuit/apps/alsijil/forms.py b/biscuit/apps/alsijil/forms.py index 53bb75524..1a0602b31 100644 --- a/biscuit/apps/alsijil/forms.py +++ b/biscuit/apps/alsijil/forms.py @@ -1,8 +1,10 @@ +from datetime import datetime + from django import forms from django.db.models import Count from django.utils.translation import ugettext_lazy as _ + from django_select2.forms import Select2Widget -from datetime import datetime from biscuit.apps.chronos.models import Room from biscuit.core.models import Group, Person @@ -13,54 +15,75 @@ from .models import LessonDocumentation, PersonalNote, PersonalNoteFilter class LessonDocumentationForm(forms.ModelForm): class Meta: model = LessonDocumentation - fields = ['topic', 'homework'] + fields = ["topic", "homework"] class PersonalNoteForm(forms.ModelForm): class Meta: model = PersonalNote - fields = ['absent', 'late', 'excused', 'remarks'] + fields = ["absent", "late", "excused", "remarks"] person_name = forms.CharField(disabled=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['person_name'].widget.attrs.update( - {'class': 'alsijil-lesson-personal-note-name'}) + self.fields["person_name"].widget.attrs.update( + {"class": "alsijil-lesson-personal-note-name"} + ) - if self.instance and getattr(self.instance, 'person', None): - self.fields['person_name'].initial = str(self.instance.person) + if self.instance and getattr(self.instance, "person", None): + self.fields["person_name"].initial = str(self.instance.person) class SelectForm(forms.Form): group = forms.ModelChoiceField( - queryset=Group.objects.annotate(lessons_count=Count('lessons')).filter(lessons_count__gt=0), - label=_('Group'), required=False, widget=Select2Widget) + queryset=Group.objects.annotate(lessons_count=Count("lessons")).filter( + lessons_count__gt=0 + ), + label=_("Group"), + required=False, + widget=Select2Widget, + ) teacher = forms.ModelChoiceField( - queryset=Person.objects.annotate(lessons_count=Count( - 'lessons_as_teacher')).filter(lessons_count__gt=0), - label=_('Teacher'), required=False, widget=Select2Widget) + queryset=Person.objects.annotate( + lessons_count=Count("lessons_as_teacher") + ).filter(lessons_count__gt=0), + label=_("Teacher"), + required=False, + widget=Select2Widget, + ) room = forms.ModelChoiceField( - queryset=Room.objects.annotate(lessons_count=Count( - 'lesson_periods')).filter(lessons_count__gt=0), - label=_('Room'), required=False, widget=Select2Widget) + queryset=Room.objects.annotate(lessons_count=Count("lesson_periods")).filter( + lessons_count__gt=0 + ), + label=_("Room"), + required=False, + widget=Select2Widget, + ) PersonalNoteFormSet = forms.modelformset_factory( - PersonalNote, form=PersonalNoteForm, max_num=0, extra=0) + PersonalNote, form=PersonalNoteForm, max_num=0, extra=0 +) class RegisterAbsenceForm(forms.Form): - date_start = forms.DateField(label=_('Start date'), widget=forms.SelectDateWidget, initial=datetime.today) - date_end = forms.DateField(label=_('End date'), widget=forms.SelectDateWidget, initial=datetime.today) - from_period = forms.IntegerField(label=_('From period'), initial=0, min_value=0) - person = forms.ModelChoiceField(label=_('Person'), queryset=Person.objects.all(), widget=Select2Widget) - absent = forms.BooleanField(label=_('Absent'), initial=True, required=False) - excused = forms.BooleanField(label=_('Excused'), initial=True, required=False) - remarks = forms.CharField(label=_('Remarks'), max_length=30, required=False) + date_start = forms.DateField( + label=_("Start date"), widget=forms.SelectDateWidget, initial=datetime.today + ) + date_end = forms.DateField( + label=_("End date"), widget=forms.SelectDateWidget, initial=datetime.today + ) + from_period = forms.IntegerField(label=_("From period"), initial=0, min_value=0) + person = forms.ModelChoiceField( + label=_("Person"), queryset=Person.objects.all(), widget=Select2Widget + ) + absent = forms.BooleanField(label=_("Absent"), initial=True, required=False) + excused = forms.BooleanField(label=_("Excused"), initial=True, required=False) + remarks = forms.CharField(label=_("Remarks"), max_length=30, required=False) class PersonalNoteFilterForm(forms.ModelForm): class Meta: model = PersonalNoteFilter - fields = ['identifier', 'description', 'regex'] + fields = ["identifier", "description", "regex"] diff --git a/biscuit/apps/alsijil/menus.py b/biscuit/apps/alsijil/menus.py index 71a57bda5..4e6abca1c 100644 --- a/biscuit/apps/alsijil/menus.py +++ b/biscuit/apps/alsijil/menus.py @@ -1,34 +1,37 @@ from django.utils.translation import ugettext_lazy as _ MENUS = { - 'NAV_MENU_CORE': [ + "NAV_MENU_CORE": [ { - 'name': _('Class register'), - 'url': '#', - 'root': True, - 'validators': ['menu_generator.validators.is_authenticated', 'biscuit.core.util.core_helpers.has_person'], - 'submenu': [ + "name": _("Class register"), + "url": "#", + "root": True, + "validators": [ + "menu_generator.validators.is_authenticated", + "biscuit.core.util.core_helpers.has_person", + ], + "submenu": [ { - 'name': _('Current lesson'), - 'url': 'lesson', - 'validators': ['menu_generator.validators.is_authenticated'] + "name": _("Current lesson"), + "url": "lesson", + "validators": ["menu_generator.validators.is_authenticated"], }, { - 'name': _('Current week'), - 'url': 'week_view', - 'validators': ['menu_generator.validators.is_authenticated'] + "name": _("Current week"), + "url": "week_view", + "validators": ["menu_generator.validators.is_authenticated"], }, { - 'name': _('Register absence'), - 'url': 'register_absence', - 'validators': ['menu_generator.validators.is_superuser'] + "name": _("Register absence"), + "url": "register_absence", + "validators": ["menu_generator.validators.is_superuser"], }, { - 'name': _('Personal note filters'), - 'url': 'list_personal_note_filters', - 'validators': ['menu_generator.validators.is_superuser'] - } - ] + "name": _("Personal note filters"), + "url": "list_personal_note_filters", + "validators": ["menu_generator.validators.is_superuser"], + }, + ], } ] } diff --git a/biscuit/apps/alsijil/migrations/0001_initial.py b/biscuit/apps/alsijil/migrations/0001_initial.py index d38957551..5de48ef84 100644 --- a/biscuit/apps/alsijil/migrations/0001_initial.py +++ b/biscuit/apps/alsijil/migrations/0001_initial.py @@ -1,8 +1,9 @@ # Generated by Django 2.2.5 on 2019-09-03 18:30 -import biscuit.core.util.core_helpers -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models + +import biscuit.core.util.core_helpers class Migration(migrations.Migration): @@ -10,42 +11,114 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('chronos', '0001_initial'), - ('core', '0001_initial'), + ("chronos", "0001_initial"), + ("core", "0001_initial"), ] operations = [ migrations.CreateModel( - name='PersonalNote', + name="PersonalNote", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('week', models.IntegerField()), - ('absent', models.BooleanField(default=False)), - ('late', models.IntegerField(default=0)), - ('excused', models.BooleanField(default=False)), - ('remarks', models.CharField(blank=True, max_length=200)), - ('lesson_period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='chronos.LessonPeriod')), - ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='personal_notes', to='core.Person')), - ('school', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.School')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("week", models.IntegerField()), + ("absent", models.BooleanField(default=False)), + ("late", models.IntegerField(default=0)), + ("excused", models.BooleanField(default=False)), + ("remarks", models.CharField(blank=True, max_length=200)), + ( + "lesson_period", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="chronos.LessonPeriod", + ), + ), + ( + "person", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="personal_notes", + to="core.Person", + ), + ), + ( + "school", + models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.CASCADE, + to="core.School", + ), + ), ], options={ - 'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period', 'person__last_name', 'person__first_name'], - 'unique_together': {('school', 'lesson_period', 'week', 'person')}, + "ordering": [ + "lesson_period__lesson__date_start", + "week", + "lesson_period__period__weekday", + "lesson_period__period__period", + "person__last_name", + "person__first_name", + ], + "unique_together": {("school", "lesson_period", "week", "person")}, }, ), migrations.CreateModel( - name='LessonDocumentation', + name="LessonDocumentation", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('week', models.IntegerField()), - ('topic', models.CharField(blank=True, max_length=200, verbose_name='Lesson topic')), - ('homework', models.CharField(blank=True, max_length=200, verbose_name='Homework')), - ('lesson_period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documentations', to='chronos.LessonPeriod')), - ('school', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.School')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("week", models.IntegerField()), + ( + "topic", + models.CharField( + blank=True, max_length=200, verbose_name="Lesson topic" + ), + ), + ( + "homework", + models.CharField( + blank=True, max_length=200, verbose_name="Homework" + ), + ), + ( + "lesson_period", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="documentations", + to="chronos.LessonPeriod", + ), + ), + ( + "school", + models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.CASCADE, + to="core.School", + ), + ), ], options={ - 'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period'], - 'unique_together': {('school', 'lesson_period', 'week')}, + "ordering": [ + "lesson_period__lesson__date_start", + "week", + "lesson_period__period__weekday", + "lesson_period__period__period", + ], + "unique_together": {("school", "lesson_period", "week")}, }, ), ] diff --git a/biscuit/apps/alsijil/migrations/0002_add_personal_note_filter.py b/biscuit/apps/alsijil/migrations/0002_add_personal_note_filter.py index 3f0fd0759..dff35d692 100644 --- a/biscuit/apps/alsijil/migrations/0002_add_personal_note_filter.py +++ b/biscuit/apps/alsijil/migrations/0002_add_personal_note_filter.py @@ -1,31 +1,66 @@ # Generated by Django 2.2.5 on 2019-11-20 14:21 +import django.db.models.deletion +from django.db import migrations, models + import biscuit.apps.alsijil.models import biscuit.core.util.core_helpers -from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('core', '0003_school_logo'), - ('alsijil', '0001_initial'), + ("core", "0003_school_logo"), + ("alsijil", "0001_initial"), ] operations = [ migrations.CreateModel( - name='PersonalNoteFilter', + name="PersonalNoteFilter", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('identifier', models.CharField(max_length=30, validators=[biscuit.apps.alsijil.models.isidentifier], verbose_name='Identifier')), - ('description', models.CharField(blank=True, max_length=60, verbose_name='Description')), - ('regex', models.CharField(max_length=100, verbose_name='Match expression')), - ('school', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.School')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "identifier", + models.CharField( + max_length=30, + validators=[biscuit.apps.alsijil.models.isidentifier], + verbose_name="Identifier", + ), + ), + ( + "description", + models.CharField( + blank=True, max_length=60, verbose_name="Description" + ), + ), + ( + "regex", + models.CharField(max_length=100, verbose_name="Match expression"), + ), + ( + "school", + models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.CASCADE, + to="core.School", + ), + ), ], options={ - 'ordering': ['identifier'], - 'unique_together': {('school', 'regex'), ('school', 'description'), ('school', 'identifier')}, + "ordering": ["identifier"], + "unique_together": { + ("school", "regex"), + ("school", "description"), + ("school", "identifier"), + }, }, ), ] diff --git a/biscuit/apps/alsijil/model_extensions.py b/biscuit/apps/alsijil/model_extensions.py index 8cbca4e2f..521e5795e 100644 --- a/biscuit/apps/alsijil/model_extensions.py +++ b/biscuit/apps/alsijil/model_extensions.py @@ -10,7 +10,14 @@ from .models import PersonalNote @Person.method -def mark_absent(self, day: date, from_period: int = 0, absent: bool = True, excused: bool = False, remarks: str = ''): +def mark_absent( + self, + day: date, + from_period: int = 0, + absent: bool = True, + excused: bool = False, + remarks: str = "", +): """ Mark a person absent for all lessons in a day, optionally starting with a selected period number. @@ -27,9 +34,7 @@ def mark_absent(self, day: date, from_period: int = 0, absent: bool = True, excu wanted_week = CalendarWeek.from_date(day) # Get all lessons of this person on the specified day - lesson_periods = self.lesson_periods_as_participant.on_day( - day - ).filter( + lesson_periods = self.lesson_periods_as_participant.on_day(day).filter( period__period__gte=from_period ) @@ -39,15 +44,12 @@ def mark_absent(self, day: date, from_period: int = 0, absent: bool = True, excu person=self, lesson_period=lesson_period, week=wanted_week.week, - defaults={ - 'absent': absent, - 'excused': excused - } + defaults={"absent": absent, "excused": excused}, ) if remarks: if personal_note.remarks: - personal_note.remarks += '; %s' % remarks + personal_note.remarks += "; %s" % remarks else: personal_note.remarks = remarks personal_note.save() @@ -69,22 +71,25 @@ def get_personal_notes(self, wanted_week: CalendarWeek): # Find all persons in the associated groups that do not yet have a personal note for this lesson missing_persons = Person.objects.annotate( - no_personal_notes=~Exists(PersonalNote.objects.filter( - week=wanted_week.week, - lesson_period=self, - person__pk=OuterRef('pk') - )) + no_personal_notes=~Exists( + PersonalNote.objects.filter( + week=wanted_week.week, lesson_period=self, person__pk=OuterRef("pk") + ) + ) ).filter( member_of__in=Group.objects.filter(pk__in=self.lesson.groups.all()), is_active=True, - no_personal_notes=True + no_personal_notes=True, ) # Create all missing personal notes - PersonalNote.objects.bulk_create([ - PersonalNote(person=person, lesson_period=self, - week=wanted_week.week) for person in missing_persons - ]) + PersonalNote.objects.bulk_create( + [ + PersonalNote(person=person, lesson_period=self, week=wanted_week.week) + for person in missing_persons + ] + ) - return PersonalNote.objects.select_related('person').filter( - lesson_period=self, week=wanted_week.week) + return PersonalNote.objects.select_related("person").filter( + lesson_period=self, week=wanted_week.week + ) diff --git a/biscuit/apps/alsijil/models.py b/biscuit/apps/alsijil/models.py index 7c7578f44..304fdb772 100644 --- a/biscuit/apps/alsijil/models.py +++ b/biscuit/apps/alsijil/models.py @@ -13,10 +13,14 @@ class PersonalNote(models.Model): absences, excuses and remarks about a student in a single lesson period. """ - person = models.ForeignKey('core.Person', models.CASCADE, related_name='personal_notes') + person = models.ForeignKey( + "core.Person", models.CASCADE, related_name="personal_notes" + ) week = models.IntegerField() - lesson_period = models.ForeignKey('chronos.LessonPeriod', models.CASCADE, related_name='personal_notes') + lesson_period = models.ForeignKey( + "chronos.LessonPeriod", models.CASCADE, related_name="personal_notes" + ) absent = models.BooleanField(default=False) late = models.IntegerField(default=0) @@ -25,9 +29,15 @@ class PersonalNote(models.Model): remarks = models.CharField(max_length=200, blank=True) class Meta: - unique_together = [['lesson_period', 'week', 'person']] - ordering = ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', - 'lesson_period__period__period', 'person__last_name', 'person__first_name'] + unique_together = [["lesson_period", "week", "person"]] + ordering = [ + "lesson_period__lesson__date_start", + "week", + "lesson_period__period__weekday", + "lesson_period__period__period", + "person__last_name", + "person__first_name", + ] class LessonDocumentation(CRUDMixin): @@ -37,27 +47,38 @@ class LessonDocumentation(CRUDMixin): week = models.IntegerField() lesson_period = models.ForeignKey( - 'chronos.LessonPeriod', models.CASCADE, related_name='documentations') + "chronos.LessonPeriod", models.CASCADE, related_name="documentations" + ) - topic = models.CharField(verbose_name=_('Lesson topic'), max_length=200, blank=True) - homework = models.CharField(verbose_name=_('Homework'), max_length=200, blank=True) + topic = models.CharField(verbose_name=_("Lesson topic"), max_length=200, blank=True) + homework = models.CharField(verbose_name=_("Homework"), max_length=200, blank=True) class Meta: - unique_together = [['lesson_period', 'week']] - ordering = ['lesson_period__lesson__date_start', 'week', - 'lesson_period__period__weekday', 'lesson_period__period__period'] + unique_together = [["lesson_period", "week"]] + ordering = [ + "lesson_period__lesson__date_start", + "week", + "lesson_period__period__weekday", + "lesson_period__period__period", + ] class PersonalNoteFilter(models.Model): """ A filter definition that can generate statistics on personal note texts. """ - identifier = models.CharField(verbose_name=_('Identifier'), max_length=30, - validators=[isidentifier], unique=True) - description = models.CharField(verbose_name=_('Description'), max_length=60, - blank=True, unique=True) + identifier = models.CharField( + verbose_name=_("Identifier"), + max_length=30, + validators=[isidentifier], + unique=True, + ) + description = models.CharField( + verbose_name=_("Description"), max_length=60, blank=True, unique=True + ) - regex = models.CharField(verbose_name=_('Match expression'), max_length=100, - unique=True) + regex = models.CharField( + verbose_name=_("Match expression"), max_length=100, unique=True + ) class Meta: - ordering = ['identifier'] + ordering = ["identifier"] diff --git a/biscuit/apps/alsijil/tables.py b/biscuit/apps/alsijil/tables.py index 83737766d..38c7402f6 100644 --- a/biscuit/apps/alsijil/tables.py +++ b/biscuit/apps/alsijil/tables.py @@ -1,14 +1,18 @@ from django.utils.translation import ugettext_lazy as _ + import django_tables2 as tables from django_tables2.utils import A class PersonalNoteFilterTable(tables.Table): class Meta: - attrs = {'class': 'table table-striped table-bordered table-hover table-responsive-xl'} + attrs = { + "class": "table table-striped table-bordered table-hover table-responsive-xl" + } identifier = tables.Column() description = tables.Column() regex = tables.Column() edit_filter = tables.LinkColumn( - 'edit_personal_note_filter', args=[A('id')], text=_('Edit')) + "edit_personal_note_filter", args=[A("id")], text=_("Edit") + ) diff --git a/biscuit/apps/alsijil/urls.py b/biscuit/apps/alsijil/urls.py index 20327ec13..85c9c25d4 100644 --- a/biscuit/apps/alsijil/urls.py +++ b/biscuit/apps/alsijil/urls.py @@ -2,24 +2,37 @@ from django.urls import path from . import views - urlpatterns = [ - path('lesson', views.lesson, name='lesson'), - path('lesson/<int:year>/<int:week>/<int:period_id>', views.lesson, - name='lesson_by_week_and_period'), - path('week', views.week_view, name='week_view'), - path('week/<int:year>/<int:week>', views.week_view, - name='week_view_by_week'), - path('print/group/<int:id_>', views.full_register_group, - name='full_register_group'), - path('absence/new', views.register_absence, - name='register_absence'), - path('filters/list', views.list_personal_note_filters, - name='list_personal_note_filters'), - path('filters/create', views.edit_personal_note_filter, - name='create_personal_note_filter'), - path('filters/edit/<int:id>', views.edit_personal_note_filter, - name='edit_personal_note_filter'), - path('filters/delete/<int:id_>', views.delete_personal_note_filter, - name='delete_personal_note_filter') + path("lesson", views.lesson, name="lesson"), + path( + "lesson/<int:year>/<int:week>/<int:period_id>", + views.lesson, + name="lesson_by_week_and_period", + ), + path("week", views.week_view, name="week_view"), + path("week/<int:year>/<int:week>", views.week_view, name="week_view_by_week"), + path( + "print/group/<int:id_>", views.full_register_group, name="full_register_group" + ), + path("absence/new", views.register_absence, name="register_absence"), + path( + "filters/list", + views.list_personal_note_filters, + name="list_personal_note_filters", + ), + path( + "filters/create", + views.edit_personal_note_filter, + name="create_personal_note_filter", + ), + path( + "filters/edit/<int:id>", + views.edit_personal_note_filter, + name="edit_personal_note_filter", + ), + path( + "filters/delete/<int:id_>", + views.delete_personal_note_filter, + name="delete_personal_note_filter", + ), ] diff --git a/biscuit/apps/alsijil/views.py b/biscuit/apps/alsijil/views.py index 1efd9f36d..837205238 100644 --- a/biscuit/apps/alsijil/views.py +++ b/biscuit/apps/alsijil/views.py @@ -13,17 +13,28 @@ from django_tables2 import RequestConfig from biscuit.apps.chronos.models import LessonPeriod from biscuit.apps.chronos.util import CalendarWeek -from biscuit.core.models import Group, Person, School from biscuit.core.decorators import admin_required +from biscuit.core.models import Group, Person, School from biscuit.core.util import messages -from .forms import LessonDocumentationForm, PersonalNoteFormSet, RegisterAbsenceForm, SelectForm, PersonalNoteFilterForm +from .forms import ( + LessonDocumentationForm, + PersonalNoteFilterForm, + PersonalNoteFormSet, + RegisterAbsenceForm, + SelectForm, +) from .models import LessonDocumentation, PersonalNoteFilter from .tables import PersonalNoteFilterTable @login_required -def lesson(request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, period_id: Optional[int] = None) -> HttpResponse: +def lesson( + request: HttpRequest, + year: Optional[int] = None, + week: Optional[int] = None, + period_id: Optional[int] = None, +) -> HttpResponse: context = {} if year and week and period_id: @@ -32,34 +43,60 @@ def lesson(request: HttpRequest, year: Optional[int] = None, week: Optional[int] wanted_week = CalendarWeek(year=year, week=week) else: # Determine current lesson by current date and time - lesson_period = LessonPeriod.objects.at_time().filter_teacher(request.user.person).first() + lesson_period = ( + LessonPeriod.objects.at_time().filter_teacher(request.user.person).first() + ) wanted_week = CalendarWeek() if lesson_period: - return redirect('lesson_by_week_and_period', wanted_week.year, wanted_week.week, lesson_period.pk) + return redirect( + "lesson_by_week_and_period", + wanted_week.year, + wanted_week.week, + lesson_period.pk, + ) else: - raise Http404(_('You either selected an invalid lesson or there is currently no lesson in progress.')) + raise Http404( + _( + "You either selected an invalid lesson or there is currently no lesson in progress." + ) + ) - if datetime.combine(wanted_week[lesson_period.period.weekday - 1], lesson_period.period.time_start) > datetime.now() and not request.user.is_superuser: - raise PermissionDenied(_('You are not allowed to create a lesson documentation for a lesson in the future.')) + if ( + datetime.combine( + wanted_week[lesson_period.period.weekday - 1], + lesson_period.period.time_start, + ) + > datetime.now() + and not request.user.is_superuser + ): + raise PermissionDenied( + _( + "You are not allowed to create a lesson documentation for a lesson in the future." + ) + ) - context['lesson_period'] = lesson_period - context['week'] = wanted_week - context['day'] = wanted_week[lesson_period.period.weekday - 1] + context["lesson_period"] = lesson_period + context["week"] = wanted_week + context["day"] = wanted_week[lesson_period.period.weekday - 1] # Create or get lesson documentation object; can be empty when first opening lesson lesson_documentation, created = LessonDocumentation.objects.get_or_create( - lesson_period=lesson_period, week=wanted_week.week) + lesson_period=lesson_period, week=wanted_week.week + ) lesson_documentation_form = LessonDocumentationForm( - request.POST or None, instance=lesson_documentation, prefix='leson_documentation') - + request.POST or None, + instance=lesson_documentation, + prefix="leson_documentation", + ) # Create a formset that holds all personal notes for all persons in this lesson persons_qs = lesson_period.get_personal_notes(wanted_week) personal_note_formset = PersonalNoteFormSet( - request.POST or None, queryset=persons_qs, prefix='personal_notes') + request.POST or None, queryset=persons_qs, prefix="personal_notes" + ) - if request.method == 'POST': + if request.method == "POST": if lesson_documentation_form.is_valid(): lesson_documentation_form.save() @@ -69,21 +106,23 @@ def lesson(request: HttpRequest, year: Optional[int] = None, week: Optional[int] # Iterate over personal notes and carry changed absences to following lessons for instance in instances: instance.person.mark_absent( - wanted_week[lesson_period.period.weekday-1], - lesson_period.period.period+1, + wanted_week[lesson_period.period.weekday - 1], + lesson_period.period.period + 1, instance.absent, - instance.excused + instance.excused, ) - context['lesson_documentation'] = lesson_documentation - context['lesson_documentation_form'] = lesson_documentation_form - context['personal_note_formset'] = personal_note_formset + context["lesson_documentation"] = lesson_documentation + context["lesson_documentation_form"] = lesson_documentation_form + context["personal_note_formset"] = personal_note_formset - return render(request, 'alsijil/lesson.html', context) + return render(request, "alsijil/lesson.html", context) @login_required -def week_view(request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None) -> HttpResponse: +def week_view( + request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None +) -> HttpResponse: context = {} if year and week: @@ -92,21 +131,25 @@ def week_view(request: HttpRequest, year: Optional[int] = None, week: Optional[i wanted_week = CalendarWeek() lesson_periods = LessonPeriod.objects.annotate( - has_documentation=Exists(LessonDocumentation.objects.filter( - ~Q(topic__exact=''), - lesson_period=OuterRef('pk'), - week=wanted_week.week - )) + has_documentation=Exists( + LessonDocumentation.objects.filter( + ~Q(topic__exact=""), lesson_period=OuterRef("pk"), week=wanted_week.week + ) + ) ).in_week(wanted_week) group = None # FIXME workaround for #38 - if request.GET.get('group', None) or request.GET.get('teacher', None) or request.GET.get('room', None): + if ( + request.GET.get("group", None) + or request.GET.get("teacher", None) + or request.GET.get("room", None) + ): lesson_periods = lesson_periods.filter_from_query(request.GET) - if 'group' in request.GET and request.GET['group']: - group = Group.objects.get(pk=request.GET['group']) + if "group" in request.GET and request.GET["group"]: + group = Group.objects.get(pk=request.GET["group"]) else: group = None - elif hasattr(request, 'user') and hasattr(request.user, 'person'): + elif hasattr(request, "user") and hasattr(request.user, "person"): group = request.user.person.owner_of.first() if group: lesson_periods = lesson_periods.filter_group(group) @@ -119,28 +162,37 @@ def week_view(request: HttpRequest, year: Optional[int] = None, week: Optional[i if lesson_periods: # Aggregate all personal notes for this group and week - persons = Person.objects.filter( - is_active=True - ).filter( - member_of__lessons__lesson_periods__in=lesson_periods - ).distinct().prefetch_related( - 'personal_notes' - ).annotate( - absences=Count('personal_notes__absent', filter=Q( - personal_notes__lesson_period__in=lesson_periods, - personal_notes__week=wanted_week.week, - personal_notes__absent=True - )), - unexcused=Count('personal_notes__absent', filter=Q( - personal_notes__lesson_period__in=lesson_periods, - personal_notes__week=wanted_week.week, - personal_notes__absent=True, - personal_notes__excused=False - )), - tardiness=Sum('personal_notes__late', filter=Q( - personal_notes__lesson_period__in=lesson_periods, - personal_notes__week=wanted_week.week - )) + persons = ( + Person.objects.filter(is_active=True) + .filter(member_of__lessons__lesson_periods__in=lesson_periods) + .distinct() + .prefetch_related("personal_notes") + .annotate( + absences=Count( + "personal_notes__absent", + filter=Q( + personal_notes__lesson_period__in=lesson_periods, + personal_notes__week=wanted_week.week, + personal_notes__absent=True, + ), + ), + unexcused=Count( + "personal_notes__absent", + filter=Q( + personal_notes__lesson_period__in=lesson_periods, + personal_notes__week=wanted_week.week, + personal_notes__absent=True, + personal_notes__excused=False, + ), + ), + tardiness=Sum( + "personal_notes__late", + filter=Q( + personal_notes__lesson_period__in=lesson_periods, + personal_notes__week=wanted_week.week, + ), + ), + ) ) else: persons = None @@ -148,19 +200,25 @@ def week_view(request: HttpRequest, year: Optional[int] = None, week: Optional[i # Add a form to filter the view select_form = SelectForm(request.GET or None) - context['current_head'] = str(wanted_week) - context['week'] = wanted_week - context['lesson_periods'] = lesson_periods - context['persons'] = persons - context['group'] = group - context['select_form'] = select_form + context["current_head"] = str(wanted_week) + context["week"] = wanted_week + context["lesson_periods"] = lesson_periods + context["persons"] = persons + context["group"] = group + context["select_form"] = select_form week_prev = wanted_week - 1 week_next = wanted_week + 1 - context['url_prev'] = '%s?%s' % (reverse('week_view_by_week', args=[week_prev.year, week_prev.week]), request.GET.urlencode()) - context['url_next'] = '%s?%s' % (reverse('week_view_by_week', args=[week_next.year, week_next.week]), request.GET.urlencode()) + context["url_prev"] = "%s?%s" % ( + reverse("week_view_by_week", args=[week_prev.year, week_prev.week]), + request.GET.urlencode(), + ) + context["url_next"] = "%s?%s" % ( + reverse("week_view_by_week", args=[week_next.year, week_next.week]), + request.GET.urlencode(), + ) - return render(request, 'alsijil/week_view.html', context) + return render(request, "alsijil/week_view.html", context) @login_required @@ -170,55 +228,76 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: group = get_object_or_404(Group, pk=id_) # Get all lesson periods for the selected group - lesson_periods = LessonPeriod.objects.filter_group( - group - ).distinct().prefetch_related( - 'documentations', 'personal_notes' + lesson_periods = ( + LessonPeriod.objects.filter_group(group) + .distinct() + .prefetch_related("documentations", "personal_notes") ) - weeks = CalendarWeek.weeks_within(School.objects.first().current_term.date_start, School.objects.first().current_term.date_end) + weeks = CalendarWeek.weeks_within( + School.objects.first().current_term.date_start, + School.objects.first().current_term.date_end, + ) periods_by_day = {} for lesson_period in lesson_periods: for week in weeks: day = week[lesson_period.period.weekday - 1] - if lesson_period.lesson.date_start <= day and lesson_period.lesson.date_end >= day: - documentations = list(filter(lambda d: d.week == week.week, lesson_period.documentations.all())) - notes = list(filter(lambda d: d.week == week.week, lesson_period.personal_notes.all())) + if ( + lesson_period.lesson.date_start <= day + and lesson_period.lesson.date_end >= day + ): + documentations = list( + filter( + lambda d: d.week == week.week, + lesson_period.documentations.all(), + ) + ) + notes = list( + filter( + lambda d: d.week == week.week, + lesson_period.personal_notes.all(), + ) + ) substitution = lesson_period.get_substitution(week.week) - periods_by_day.setdefault(day, []).append((lesson_period, documentations, notes, substitution)) + periods_by_day.setdefault(day, []).append( + (lesson_period, documentations, notes, substitution) + ) persons = group.members.annotate( - absences=Count('personal_notes__absent', filter=Q( - personal_notes__absent=True - )), - unexcused=Count('personal_notes__absent', filter=Q( - personal_notes__absent=True, - personal_notes__excused=False - )), - tardiness=Sum('personal_notes__late') + absences=Count("personal_notes__absent", filter=Q(personal_notes__absent=True)), + unexcused=Count( + "personal_notes__absent", + filter=Q(personal_notes__absent=True, personal_notes__excused=False), + ), + tardiness=Sum("personal_notes__late"), ) # FIXME Move to manager personal_note_filters = PersonalNoteFilter.objects.all() for personal_note_filter in personal_note_filters: persons = persons.annotate( - **{'_personal_notes_with_%s' % personal_note_filter.identifier: Count( - 'personal_notes__remarks', - filter=Q(personal_notes__remarks__iregex=personal_note_filter.regex) - )} + **{ + "_personal_notes_with_%s" + % personal_note_filter.identifier: Count( + "personal_notes__remarks", + filter=Q( + personal_notes__remarks__iregex=personal_note_filter.regex + ), + ) + } ) - context['persons'] = persons - context['personal_note_filters'] = personal_note_filters - context['group'] = group - context['weeks'] = weeks - context['periods_by_day'] = periods_by_day - context['today'] = date.today() - context['school'] = School.objects.first() + context["persons"] = persons + context["personal_note_filters"] = personal_note_filters + context["group"] = group + context["weeks"] = weeks + context["periods_by_day"] = periods_by_day + context["today"] = date.today() + context["school"] = School.objects.first() - return render(request, 'alsijil/print/full_register.html', context) + return render(request, "alsijil/print/full_register.html", context) @admin_required @@ -227,30 +306,30 @@ def register_absence(request: HttpRequest) -> HttpResponse: register_absence_form = RegisterAbsenceForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": if register_absence_form.is_valid(): # Get data from form - person = register_absence_form.cleaned_data['person'] - start_date = register_absence_form.cleaned_data['date_start'] - end_date = register_absence_form.cleaned_data['date_end'] - from_period = register_absence_form.cleaned_data['from_period'] - absent = register_absence_form.cleaned_data['absent'] - excused = register_absence_form.cleaned_data['excused'] - remarks = register_absence_form.cleaned_data['remarks'] + person = register_absence_form.cleaned_data["person"] + start_date = register_absence_form.cleaned_data["date_start"] + end_date = register_absence_form.cleaned_data["date_end"] + from_period = register_absence_form.cleaned_data["from_period"] + absent = register_absence_form.cleaned_data["absent"] + excused = register_absence_form.cleaned_data["excused"] + remarks = register_absence_form.cleaned_data["remarks"] # Mark person as absent delta = end_date - start_date - for i in range(delta.days+1): + for i in range(delta.days + 1): from_period = from_period if i == 0 else 0 day = start_date + timedelta(days=i) person.mark_absent(day, from_period, absent, excused, remarks) - messages.success(request, _('The absence has been saved.')) - return redirect('index') + messages.success(request, _("The absence has been saved.")) + return redirect("index") - context['register_absence_form'] = register_absence_form + context["register_absence_form"] = register_absence_form - return render(request, 'alsijil/register_absence.html', context) + return render(request, "alsijil/register_absence.html", context) def list_personal_note_filters(request: HttpRequest) -> HttpResponse: @@ -262,33 +341,36 @@ def list_personal_note_filters(request: HttpRequest) -> HttpResponse: personal_note_filters_table = PersonalNoteFilterTable(personal_note_filters) RequestConfig(request).configure(personal_note_filters_table) - context['personal_note_filters_table'] = personal_note_filters_table + context["personal_note_filters_table"] = personal_note_filters_table - return render(request, 'alsijil/personal_note_filters.html', context) + return render(request, "alsijil/personal_note_filters.html", context) -def edit_personal_note_filter(request: HttpRequest, id: Optional['int'] = None) -> HttpResponse: +def edit_personal_note_filter( + request: HttpRequest, id: Optional["int"] = None +) -> HttpResponse: context = {} if id: personal_note_filter = PersonalNoteFilter.objects.get(id=id) - context['personal_note_filter'] = personal_note_filter + context["personal_note_filter"] = personal_note_filter personal_note_filter_form = PersonalNoteFilterForm( - request.POST or None, instance=personal_note_filter) + request.POST or None, instance=personal_note_filter + ) else: - personal_note_filter_form = PersonalNoteFilterForm( - request.POST or None) - - if request.method == 'POST': + personal_note_filter_form = PersonalNoteFilterForm(request.POST or None) + + if request.method == "POST": if personal_note_filter_form.is_valid(): personal_note_filter_form.save(commit=True) - messages.success(request, _('The filter has been saved')) - return redirect('list_personal_note_filters') + messages.success(request, _("The filter has been saved")) + return redirect("list_personal_note_filters") - context['personal_note_filter_form'] = personal_note_filter_form + context["personal_note_filter_form"] = personal_note_filter_form + + return render(request, "alsijil/manage_personal_note_filter.html", context) - return render(request, 'alsijil/manage_personal_note_filter.html', context) @admin_required def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse: @@ -297,8 +379,8 @@ def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse: personal_note_filter = get_object_or_404(PersonalNoteFilter, pk=id_) PersonalNoteFilter.objects.filter(pk=id_).delete() - - messages.success(request, _('The filter has been deleted.')) - context['personal_note_filter'] = personal_note_filter - return redirect('list_personal_note_filters') + messages.success(request, _("The filter has been deleted.")) + + context["personal_note_filter"] = personal_note_filter + return redirect("list_personal_note_filters") -- GitLab