diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py index ce997f31a12e056bf72aad7abe21242941e850fe..5a2f2d53e9acbc006c1ae8db472a88e071fd9212 100644 --- a/aleksis/apps/alsijil/model_extensions.py +++ b/aleksis/apps/alsijil/model_extensions.py @@ -4,6 +4,7 @@ from typing import Dict, Optional, Union from django.db.models import Exists, OuterRef, QuerySet from django.utils.translation import gettext as _ +import reversion from calendarweek import CalendarWeek from aleksis.apps.chronos.models import LessonPeriod @@ -37,8 +38,10 @@ def mark_absent( 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( - period__period__gte=from_period + lesson_periods = ( + self.lesson_periods_as_participant.on_day(day) + .filter(period__period__gte=from_period) + .annotate_week(wanted_week) ) if to_period: @@ -46,21 +49,30 @@ def mark_absent( # Create and update all personal notes for the discovered lesson periods for lesson_period in lesson_periods: - personal_note, created = PersonalNote.objects.update_or_create( - person=self, - lesson_period=lesson_period, - week=wanted_week.week, - year=wanted_week.year, - defaults={"absent": absent, "excused": excused, "excuse_type": excuse_type}, - ) - personal_note.groups_of_person.set(self.member_of.all()) - - if remarks: - if personal_note.remarks: - personal_note.remarks += "; %s" % remarks - else: - personal_note.remarks = remarks - personal_note.save() + sub = lesson_period.get_substitution() + if sub and sub.is_cancelled: + continue + + with reversion.create_revision(): + personal_note, created = PersonalNote.objects.update_or_create( + person=self, + lesson_period=lesson_period, + week=wanted_week.week, + year=wanted_week.year, + defaults={ + "absent": absent, + "excused": excused, + "excuse_type": excuse_type, + }, + ) + personal_note.groups_of_person.set(self.member_of.all()) + + if remarks: + if personal_note.remarks: + personal_note.remarks += "; %s" % remarks + else: + personal_note.remarks = remarks + personal_note.save() @LessonPeriod.method diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py index 799e0d01a9d90dd611aca288d332f974a644554c..66f6477d22165c085abd0855502686d505d75c75 100644 --- a/aleksis/apps/alsijil/models.py +++ b/aleksis/apps/alsijil/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils.formats import date_format from django.utils.translation import gettext_lazy as _ from calendarweek import CalendarWeek @@ -82,6 +83,25 @@ class PersonalNote(ExtensibleModel, WeekRelatedMixin): self.excuse_type = None super().save(*args, **kwargs) + def reset_values(self): + """Reset all saved data to default values. + + .. warning :: + + This won't save the data, please execute ``save`` extra. + """ + defaults = PersonalNote() + + self.absent = defaults.absent + self.late = defaults.late + self.excused = defaults.excused + self.excuse_type = defaults.excuse_type + self.remarks = defaults.remarks + self.extra_marks.clear() + + def __str__(self): + return f"{date_format(self.date)}, {self.lesson_period}, {self.person}" + class Meta: verbose_name = _("Personal note") verbose_name_plural = _("Personal notes") diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html index 7b53c558dab2e5cf5f35f5363568f224ae80f9b3..be134d99139fed49d0e93ee4c39d7e5dc5dedec3 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html @@ -32,6 +32,10 @@ {% trans "Mark as" %} <input type="hidden" value="{{ note.pk }}" name="personal_note"> {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> </form> {% endif %} <i class="material-icons left red-text">warning</i> @@ -47,6 +51,10 @@ {% trans "Mark as" %} <input type="hidden" value="{{ note.pk }}" name="personal_note"> {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> </form> {% endif %} </li> @@ -167,6 +175,10 @@ {% trans "Mark as" %} <input type="hidden" value="{{ note.pk }}" name="personal_note"> {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> </form> {% endif %} @@ -205,6 +217,10 @@ {% trans "Mark as" %} <input type="hidden" value="{{ note.pk }}" name="personal_note"> {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> </form> {% endif %} </div> diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py index 0482571bd3cd9cf7c7da4a15b4cd7fc3e0a58c36..e2bba60a0df002ccf4b110ea8ac5f1e22df8387a 100644 --- a/aleksis/apps/alsijil/urls.py +++ b/aleksis/apps/alsijil/urls.py @@ -29,6 +29,11 @@ urlpatterns = [ path("persons/", views.my_students, name="my_students"), path("persons/<int:id_>/", views.overview_person, name="overview_person"), path("me/", views.overview_person, name="overview_me"), + path( + "notes/<int:pk>/delete/", + views.DeletePersonalNoteView.as_view(), + name="delete_personal_note", + ), path("absence/new", views.register_absence, name="register_absence"), path("extra_marks/", views.ExtraMarkListView.as_view(), name="extra_marks"), path( diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 3fb49fea616b6b7d8e0dfb770af80b32828c49e4..b3da8f289641c9df21fa14402e659688e2cd6b3f 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -7,7 +7,9 @@ from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse, reverse_lazy from django.utils.translation import ugettext as _ +from django.views.generic import DetailView +import reversion from calendarweek import CalendarWeek from django_tables2 import SingleTableView from reversion.views import RevisionMixin @@ -131,7 +133,8 @@ def lesson( if personal_note_formset.is_valid() and request.user.has_perm( "alsijil.edit_lesson_personalnote", lesson_period ): - instances = personal_note_formset.save() + with reversion.create_revision(): + instances = personal_note_formset.save() # Iterate over personal notes and carry changed absences to following lessons for instance in instances: @@ -530,7 +533,12 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp absent=True, excused=False, ) - notes.update(excused=True, excuse_type=excuse_type) + for note in notes: + note.excused = True + note.excuse_type = excuse_type + with reversion.create_revision(): + note.save() + messages.success( request, _("The absences have been marked as excused.") ) @@ -547,7 +555,8 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp if note.absent: note.excused = True note.excuse_type = excuse_type - note.save() + with reversion.create_revision(): + note.save() messages.success( request, _("The absence has been marked as excused.") ) @@ -678,6 +687,19 @@ def register_absence(request: HttpRequest) -> HttpResponse: return render(request, "alsijil/absences/register.html", context) +class DeletePersonalNoteView(DetailView): + model = PersonalNote + template_name = "core/pages/delete.html" + + def post(self, request, *args, **kwargs): + note = self.get_object() + with reversion.create_revision(): + note.reset_values() + note.save() + messages.success(request, _("The personal note has been deleted.")) + return redirect("overview_person", note.person.pk) + + class ExtraMarkListView(PermissionRequiredMixin, SingleTableView): """Table of all extra marks."""