Skip to content
Snippets Groups Projects
Verified Commit 29e6a6ab authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Fix lint issues and reformat all files

parent c940fbce
No related branches found
No related tags found
1 merge request!53Fix lint issues and reformat all files
Pipeline #2753 passed
from datetime import datetime
from aleksis.apps.chronos.managers import TimetableType
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Count
from django.utils.translation import gettext_lazy as _
from django_select2.forms import Select2Widget
from material import Layout, Row
from material import Row, Layout
from aleksis.apps.chronos.managers import TimetableType
from aleksis.core.models import Group, Person
from .models import LessonDocumentation, PersonalNote, PersonalNoteFilter
......@@ -43,15 +42,17 @@ class SelectForm(forms.Form):
layout = Layout(Row("group", "teacher"))
group = forms.ModelChoiceField(
queryset=Group.objects.annotate(lessons_count=Count("lessons")).filter(lessons_count__gt=0),
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
),
queryset=Person.objects.annotate(
lessons_count=Count("lessons_as_teacher")
).filter(lessons_count__gt=0),
label=_("Teacher"),
required=False,
widget=Select2Widget,
......@@ -60,7 +61,7 @@ class SelectForm(forms.Form):
def clean(self) -> dict:
data = super().clean()
if data.get("group") and not data.get("teacher") :
if data.get("group") and not data.get("teacher"):
type_ = TimetableType.GROUP
instance = data["group"]
elif data.get("teacher") and not data.get("group"):
......@@ -75,24 +76,22 @@ class SelectForm(forms.Form):
data["instance"] = instance
return data
PersonalNoteFormSet = forms.modelformset_factory(
PersonalNote, form=PersonalNoteForm, max_num=0, extra=0
)
class RegisterAbsenceForm(forms.Form):
layout = Layout(Row("date_start", "date_end"),
Row("from_period"),
Row("absent", "excused"),
Row("person"),
Row("remarks")
)
date_start = forms.DateField(
label=_("Start date"), initial=datetime.today
)
date_end = forms.DateField(
label=_("End date"), initial=datetime.today
layout = Layout(
Row("date_start", "date_end"),
Row("from_period"),
Row("absent", "excused"),
Row("person"),
Row("remarks"),
)
date_start = forms.DateField(label=_("Start date"), initial=datetime.today)
date_end = forms.DateField(label=_("End date"), 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
......
# Generated by Django 3.0.6 on 2020-05-29 10:29
import aleksis.apps.alsijil.models
import django.contrib.postgres.fields.jsonb
import django.contrib.sites.managers
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models
import aleksis.apps.alsijil.models
class Migration(migrations.Migration):
......@@ -12,74 +13,195 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('core', '0001_initial'),
('chronos', '0001_initial'),
('sites', '0002_alter_domain_unique'),
("core", "0001_initial"),
("chronos", "0001_initial"),
("sites", "0002_alter_domain_unique"),
]
operations = [
migrations.CreateModel(
name='PersonalNoteFilter',
name="PersonalNoteFilter",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
('identifier', models.CharField(max_length=30, unique=True, validators=[aleksis.apps.alsijil.models.isidentifier], verbose_name='Identifier')),
('description', models.CharField(blank=True, max_length=60, unique=True, verbose_name='Description')),
('regex', models.CharField(max_length=100, unique=True, verbose_name='Match expression')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"extended_data",
django.contrib.postgres.fields.jsonb.JSONField(
default=dict, editable=False
),
),
(
"identifier",
models.CharField(
max_length=30,
unique=True,
validators=[aleksis.apps.alsijil.models.isidentifier],
verbose_name="Identifier",
),
),
(
"description",
models.CharField(
blank=True,
max_length=60,
unique=True,
verbose_name="Description",
),
),
(
"regex",
models.CharField(
max_length=100, unique=True, verbose_name="Match expression"
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
'verbose_name': 'Personal note filter',
'verbose_name_plural': 'Personal note filters',
'ordering': ['identifier'],
"verbose_name": "Personal note filter",
"verbose_name_plural": "Personal note filters",
"ordering": ["identifier"],
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
),
migrations.CreateModel(
name='PersonalNote',
name="PersonalNote",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
('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, related_name='personal_notes', to='chronos.LessonPeriod')),
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='personal_notes', to='core.Person')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"extended_data",
django.contrib.postgres.fields.jsonb.JSONField(
default=dict, editable=False
),
),
("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,
related_name="personal_notes",
to="chronos.LessonPeriod",
),
),
(
"person",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="personal_notes",
to="core.Person",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
'verbose_name': 'Personal note',
'verbose_name_plural': 'Personal notes',
'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')},
"verbose_name": "Personal note",
"verbose_name_plural": "Personal notes",
"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")},
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
),
migrations.CreateModel(
name='LessonDocumentation',
name="LessonDocumentation",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
('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')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"extended_data",
django.contrib.postgres.fields.jsonb.JSONField(
default=dict, editable=False
),
),
("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",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
'verbose_name': 'Lesson documentation',
'verbose_name_plural': 'Lesson documentations',
'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period'],
'unique_together': {('lesson_period', 'week')},
"verbose_name": "Lesson documentation",
"verbose_name_plural": "Lesson documentations",
"ordering": [
"lesson_period__lesson__date_start",
"week",
"lesson_period__period__weekday",
"lesson_period__period__period",
],
"unique_together": {("lesson_period", "week")},
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
),
]
from datetime import date
from django.db.models import Exists, F, OuterRef
from django.db.models import Exists, OuterRef
from calendarweek import CalendarWeek
......@@ -19,9 +19,8 @@ def mark_absent(
excused: bool = False,
remarks: str = "",
):
""" Mark a person absent for all lessons in a day, optionally starting with
a selected period number.
"""Mark a person absent for all lessons in a day, optionally starting with a selected period number.
This function creates `PersonalNote` objects for every `LessonPeriod` the person
participates in on the selected day and marks them as absent/excused.
......@@ -31,7 +30,6 @@ def mark_absent(
:Authors:
- Dominik George <dominik.george@teckids.org>
"""
wanted_week = CalendarWeek.from_date(day)
# Get all lessons of this person on the specified day
......@@ -58,18 +56,17 @@ def mark_absent(
@LessonPeriod.method
def get_personal_notes(self, wanted_week: CalendarWeek):
""" Get all personal notes for that lesson in a specified week.
"""Get all personal notes for that lesson in a specified week.
Returns all linked `PersonalNote` objects, filtered by the given weeek,
creating those objects that haven't been created yet.
..note:: Only available when AlekSIS-App-Alsijil is installed.
:Date: 2019-11-09
:Authors:
- Dominik George <dominik.george@teckids.org>
"""
# 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(
......
......@@ -9,11 +9,15 @@ def isidentifier(value: str) -> bool:
class PersonalNote(ExtensibleModel):
""" A personal note about a single person. Used in the class register to note
absences, excuses and remarks about a student in a single lesson period.
"""A personal note about a single person.
Used in the class register to note 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(
......@@ -41,8 +45,9 @@ class PersonalNote(ExtensibleModel):
class LessonDocumentation(ExtensibleModel):
""" A documentation on a single lesson period. Non-personal, includes
the topic and homework of the lesson.
"""A documentation on a single lesson period.
Non-personal, includes the topic and homework of the lesson.
"""
week = models.IntegerField()
......@@ -66,16 +71,21 @@ class LessonDocumentation(ExtensibleModel):
class PersonalNoteFilter(ExtensibleModel):
""" A filter definition that can generate statistics on personal note texts. """
"""A filter definition that can generate statistics on personal note texts."""
identifier = models.CharField(
verbose_name=_("Identifier"), max_length=30, validators=[isidentifier], unique=True,
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:
verbose_name = _("Personal note filter")
......
......@@ -12,13 +12,29 @@ urlpatterns = [
path("week", views.week_view, name="week_view"),
path("week/<int:year>/<int:week>", views.week_view, name="week_view_by_week"),
path("week/<str:type_>/<int:id_>/", views.week_view, name="week_view"),
path("week/<int:year>/<int:week>/<str:type_>/<int:id_>/", views.week_view, name="week_view_by_week"),
path("print/group/<int:id_>", views.full_register_group, name="full_register_group"),
path(
"week/<int:year>/<int:week>/<str:type_>/<int:id_>/",
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",
"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_>",
......
from datetime import date, datetime, timedelta
from typing import Optional
from aleksis.apps.chronos.managers import TimetableType
from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
from django.core.exceptions import PermissionDenied
from django.db.models import Count, Exists, OuterRef, Q, Sum
from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
......@@ -13,7 +11,9 @@ from django.utils.translation import ugettext as _
from calendarweek import CalendarWeek
from django_tables2 import RequestConfig
from aleksis.apps.chronos.managers import TimetableType
from aleksis.apps.chronos.models import LessonPeriod
from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
from aleksis.core.models import Group, Person, SchoolTerm
from aleksis.core.util import messages
......@@ -42,29 +42,38 @@ def lesson(
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,
"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."
"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,
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.")
_(
"You are not allowed to create a lesson documentation for a lesson in the future."
)
)
context["lesson_period"] = lesson_period
......@@ -76,7 +85,9 @@ def lesson(
lesson_period=lesson_period, week=wanted_week.week
)
lesson_documentation_form = LessonDocumentationForm(
request.POST or None, instance=lesson_documentation, prefix="lesson_documentation",
request.POST or None,
instance=lesson_documentation,
prefix="lesson_documentation",
)
# Create a formset that holds all personal notes for all persons in this lesson
......@@ -109,7 +120,11 @@ def lesson(
def week_view(
request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, type_: Optional[str] = None, id_: Optional[int] = None
request: HttpRequest,
year: Optional[int] = None,
week: Optional[int] = None,
type_: Optional[str] = None,
id_: Optional[int] = None,
) -> HttpResponse:
context = {}
......@@ -161,8 +176,13 @@ def week_view(
if "type_" not in select_form.cleaned_data:
return redirect("week_view_by_week", wanted_week.year, wanted_week.week)
else:
return redirect("week_view_by_week", wanted_week.year, wanted_week.week,
select_form.cleaned_data["type_"].value, select_form.cleaned_data["instance"].pk)
return redirect(
"week_view_by_week",
wanted_week.year,
wanted_week.week,
select_form.cleaned_data["type_"].value,
select_form.cleaned_data["instance"].pk,
)
if lesson_periods:
# Aggregate all personal notes for this group and week
......@@ -203,7 +223,9 @@ def week_view(
persons = None
# Resort lesson periods manually because an union queryset doesn't support order_by
lesson_periods = sorted(lesson_periods, key=lambda x: (x.period.weekday, x.period.period))
lesson_periods = sorted(
lesson_periods, key=lambda x: (x.period.weekday, x.period.period)
)
context["week"] = wanted_week
context["lesson_periods"] = lesson_periods
......@@ -234,8 +256,8 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
# Get all lesson periods for the selected group
lesson_periods = (
LessonPeriod.objects.filter_group(group)
.distinct()
.prefetch_related("documentations", "personal_notes")
.distinct()
.prefetch_related("documentations", "personal_notes")
)
current_school_term = SchoolTerm.current
......@@ -244,8 +266,7 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
return HttpResponseNotFound(_("There is no current school term."))
weeks = CalendarWeek.weeks_within(
current_school_term.date_start,
current_school_term.date_end,
current_school_term.date_start, current_school_term.date_end,
)
periods_by_day = {}
......@@ -255,10 +276,16 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
if lesson_period.lesson.date_start <= day <= lesson_period.lesson.date_end:
documentations = list(
filter(lambda d: d.week == week.week, lesson_period.documentations.all(),)
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(),)
filter(
lambda d: d.week == week.week,
lesson_period.personal_notes.all(),
)
)
substitution = lesson_period.get_substitution(week.week)
......@@ -267,7 +294,9 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
)
persons = group.members.annotate(
absences_count=Count("personal_notes__absent", filter=Q(personal_notes__absent=True)),
absences_count=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),
......@@ -283,7 +312,9 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
"_personal_notes_with_%s"
% personal_note_filter.identifier: Count(
"personal_notes__remarks",
filter=Q(personal_notes__remarks__iregex=personal_note_filter.regex),
filter=Q(
personal_notes__remarks__iregex=personal_note_filter.regex
),
)
}
)
......@@ -343,7 +374,9 @@ def list_personal_note_filters(request: HttpRequest) -> HttpResponse:
return render(request, "alsijil/personal_note_filter/list.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:
......
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