diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 556b6f5b29fef2433c6f082a3af3a7b14e188bc2..7f099fb3ecfd23c0909f86f2928a7d81eb8c8aeb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ Unreleased Fixed ~~~~~ +* Register absence form wasn't accessible without direct access to class register. +* Printing the full group register failed when a person had no personal notes. +* Data checks reported all Lesson Documentations as being during Holidays if there was no Holiday object. * Students were displayed multiple times in class register views. * Absences were counted multiple times in some class register views. diff --git a/aleksis/apps/alsijil/data_checks.py b/aleksis/apps/alsijil/data_checks.py index 864f019646411443605b0495075ba6acfb47219b..cb056e8cb3728a01c98e110f15e12da629df7ff9 100644 --- a/aleksis/apps/alsijil/data_checks.py +++ b/aleksis/apps/alsijil/data_checks.py @@ -113,7 +113,7 @@ class LessonDocumentationOnHolidaysDataCheck(DataCheck): documentations = LessonDocumentation.objects.not_empty().annotate_date_range() - q = Q() + q = Q(pk__in=[]) for holiday in holidays: q = q | Q(day_end__gte=holiday.date_start, day_start__lte=holiday.date_end) documentations = documentations.filter(q) @@ -147,7 +147,7 @@ class PersonalNoteOnHolidaysDataCheck(DataCheck): personal_notes = PersonalNote.objects.not_empty().annotate_date_range() - q = Q() + q = Q(pk__in=[]) for holiday in holidays: q = q | Q(day_end__gte=holiday.date_start, day_start__lte=holiday.date_end) personal_notes = personal_notes.filter(q) diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py index f9aced0507b00540890eb58fe3d3ce978fa053d1..5c2578b7d435e1b2240c848212d3b062c4a26db5 100644 --- a/aleksis/apps/alsijil/forms.py +++ b/aleksis/apps/alsijil/forms.py @@ -186,9 +186,11 @@ PersonalNoteFormSet = forms.modelformset_factory( class RegisterAbsenceForm(forms.Form): layout = Layout( + Fieldset("", "person"), Fieldset("", Row("date_start", "date_end"), Row("from_period", "to_period")), Fieldset("", Row("absent", "excused"), Row("excuse_type"), Row("remarks")), ) + person = forms.ModelChoiceField(label=_("Person"), queryset=None, widget=Select2Widget) date_start = forms.DateField(label=_("Start date"), initial=datetime.today) date_end = forms.DateField(label=_("End date"), initial=datetime.today) from_period = forms.ChoiceField(label=_("Start period")) @@ -203,10 +205,30 @@ class RegisterAbsenceForm(forms.Form): ) remarks = forms.CharField(label=_("Remarks"), max_length=30, required=False) - def __init__(self, *args, **kwargs): + def __init__(self, request, *args, **kwargs): + self.request = request super().__init__(*args, **kwargs) period_choices = TimePeriod.period_choices + if self.request.user.has_perm("alsijil.register_absence"): + self.fields["person"].queryset = Person.objects.all() + else: + persons_qs = Person.objects.filter( + Q( + pk__in=get_objects_for_user( + self.request.user, "core.register_absence_person", Person + ) + ) + | Q(primary_group__owners=self.request.user.person) + | Q( + member_of__in=get_objects_for_user( + self.request.user, "core.register_absence_group", Group + ) + ) + ).distinct() + + self.fields["person"].queryset = persons_qs + self.fields["from_period"].choices = period_choices self.fields["to_period"].choices = period_choices self.fields["from_period"].initial = TimePeriod.period_min diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py index eb2f7e0a61f815c3a2f39f22707940065d5de39d..96ed7ef5ac48927bf16cc11a881314c51fcd486b 100644 --- a/aleksis/apps/alsijil/menus.py +++ b/aleksis/apps/alsijil/menus.py @@ -89,6 +89,17 @@ MENUS = { ), ], }, + { + "name": _("Register absence"), + "url": "register_absence", + "icon": "rate_review", + "validators": [ + ( + "aleksis.core.util.predicates.permission_validator", + "alsijil.view_register_absence_rule", + ), + ], + }, { "name": _("Excuse types"), "url": "excuse_types", diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py index b2640b8cfbf2eb8a1874926ee5a5bce2809ef1dd..e9011c6c2b33ed58a21b6412f6c7e366b1b5e49e 100644 --- a/aleksis/apps/alsijil/rules.py +++ b/aleksis/apps/alsijil/rules.py @@ -156,15 +156,20 @@ view_week_personal_notes_predicate = has_person & ( add_perm("alsijil.view_week_personalnote_rule", view_week_personal_notes_predicate) # Register absence -register_absence_predicate = has_person & ( +view_register_absence_predicate = has_person & ( ( is_person_group_owner & is_site_preference_set("alsijil", "register_absence_as_primary_group_owner") ) | has_global_perm("alsijil.register_absence") +) + +register_absence_predicate = has_person & ( + view_register_absence_predicate | has_object_perm("core.register_absence_person") | has_person_group_object_perm("core.register_absence_group") ) +add_perm("alsijil.view_register_absence_rule", view_register_absence_predicate) add_perm("alsijil.register_absence_rule", register_absence_predicate) # View full register for group diff --git a/aleksis/apps/alsijil/templates/alsijil/absences/register.html b/aleksis/apps/alsijil/templates/alsijil/absences/register.html index 5452de10e44ca52dd75de373dcb43fe11c29bbf8..590ad1e1f61d5ed09210101012aadaae9dda6f25 100644 --- a/aleksis/apps/alsijil/templates/alsijil/absences/register.html +++ b/aleksis/apps/alsijil/templates/alsijil/absences/register.html @@ -1,13 +1,16 @@ {# -*- engine:django -*- #} {% extends "core/base.html" %} -{% load material_form i18n static %} +{% load material_form i18n static any_js %} {% block browser_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %} {% block page_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %} -{% block content %} - <h6>{% trans "Person" %}: {{ person }}</h6> +{% block extra_head %} + {{ form.media.css }} + {% include_css "select2-materialize" %} +{% endblock %} +{% block content %} <form method="post"> {% csrf_token %} {% form form=register_absence_form %}{% endform %} @@ -22,4 +25,7 @@ }); }); </script> + + {% include_js "select2-materialize" %} + {{ form.media.js }} {% endblock %} diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py index b004185915df6cc72c9f121a1061e04f3d969e65..b06aebd352774727bb6bddca9dec8a0e28846a69 100644 --- a/aleksis/apps/alsijil/urls.py +++ b/aleksis/apps/alsijil/urls.py @@ -48,6 +48,7 @@ urlpatterns = [ name="delete_personal_note", ), path("absence/new/<int:id_>/", views.register_absence, name="register_absence"), + path("absence/new/", views.register_absence, name="register_absence"), path("extra_marks/", views.ExtraMarkListView.as_view(), name="extra_marks"), path( "extra_marks/create/", diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 538b24e7d13f0fa991ec5b412ec975e4700cc71d..68833a4d5dd8814a58c3bf6cae6b1c2e2c7af701 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -742,7 +742,7 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: prefetched_persons = [] for person in persons: - person.filtered_notes = sorted_personal_notes["person"][person.pk] + person.filtered_notes = sorted_personal_notes["person"].get(person.pk, []) prefetched_persons.append(person) context["school_term"] = group.school_term @@ -1070,18 +1070,27 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp @never_cache @permission_required("alsijil.register_absence_rule", fn=objectgetter_optional(Person)) -def register_absence(request: HttpRequest, id_: int) -> HttpResponse: +def register_absence(request: HttpRequest, id_: int = None) -> HttpResponse: context = {} - person = get_object_or_404(Person, pk=id_) + if id_: + person = get_object_or_404(Person, pk=id_) + else: + person = None - register_absence_form = RegisterAbsenceForm(request.POST or None) + register_absence_form = RegisterAbsenceForm( + request, request.POST or None, initial={"person": person} + ) - if request.method == "POST" and register_absence_form.is_valid(): + if ( + request.method == "POST" + and register_absence_form.is_valid() + and request.user.has_perm("alsijil.register_absence_rule", person) + ): confirmed = request.POST.get("confirmed", "0") == "1" # Get data from form - # person = register_absence_form.cleaned_data["person"] + 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"]