diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py index 3d7f554eb2750784c3217eeaff4c09baae330520..99954b5308595d789eb3dca3a1e8ecf3602b9f6f 100644 --- a/aleksis/apps/alsijil/forms.py +++ b/aleksis/apps/alsijil/forms.py @@ -11,7 +11,7 @@ from material import Layout, Row from aleksis.apps.chronos.managers import TimetableType from aleksis.core.models import Group, Person -from .models import LessonDocumentation, PersonalNote, PersonalNoteFilter +from .models import ExcuseType, LessonDocumentation, PersonalNote, PersonalNoteFilter class LessonDocumentationForm(forms.ModelForm): @@ -116,3 +116,11 @@ class PersonalNoteFilterForm(forms.ModelForm): class Meta: model = PersonalNoteFilter fields = ["identifier", "description", "regex"] + + +class ExcuseTypeForm(forms.ModelForm): + layout = Layout("short_name", "name") + + class Meta: + model = ExcuseType + fields = ["short_name", "name"] diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py index 2b84cb6f7f70b644a34f79f170dfc4cb6751f773..c5fea59e3790fba0407d55d760434ac2e3dd0d3d 100644 --- a/aleksis/apps/alsijil/menus.py +++ b/aleksis/apps/alsijil/menus.py @@ -36,6 +36,12 @@ MENUS = { "icon": "filter_list", "validators": ["menu_generator.validators.is_superuser"], }, + { + "name": _("Excuse types"), + "url": "excuse_types", + "icon": "label", + "validators": ["menu_generator.validators.is_superuser"], + }, ], } ] diff --git a/aleksis/apps/alsijil/tables.py b/aleksis/apps/alsijil/tables.py index bad0dc9f3923421035d0701251012461df13fec8..3a6762c3744ead9d02e9917aa975b530b5e448f0 100644 --- a/aleksis/apps/alsijil/tables.py +++ b/aleksis/apps/alsijil/tables.py @@ -17,3 +17,23 @@ class PersonalNoteFilterTable(tables.Table): text=_("Edit"), attrs={"a": {"class": "btn-flat waves-effect waves-orange"}}, ) + + +class ExcuseTypeTable(tables.Table): + class Meta: + attrs = {"class": "highlight"} + + name = tables.LinkColumn("edit_excuse_type", args=[A("id")]) + short_name = tables.Column() + edit = tables.LinkColumn( + "edit_excuse_type", + args=[A("id")], + text=_("Edit"), + attrs={"a": {"class": "btn-flat waves-effect waves-orange orange-text"}}, + ) + delete = tables.LinkColumn( + "delete_excuse_type", + args=[A("id")], + text=_("Delete"), + attrs={"a": {"class": "btn-flat waves-effect waves-red red-text"}}, + ) diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/create.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/create.html new file mode 100644 index 0000000000000000000000000000000000000000..6fc6faefb2543cecf32b02e7dcb7ea2a40f3d73b --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/create.html @@ -0,0 +1,18 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} +{% load material_form i18n %} + +{% block browser_title %}{% blocktrans %}Create excuse type{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Create excuse type{% endblocktrans %}{% endblock %} + +{% block content %} + {% include "alsijil/excuse_type/warning.html" %} + + <form method="post"> + {% csrf_token %} + {% form form=form %}{% endform %} + {% include "core/partials/save_button.html" %} + </form> + +{% endblock %} diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/edit.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..78396ed66264cc19abdac2085d1cc89ff931bb38 --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/edit.html @@ -0,0 +1,17 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} +{% load material_form i18n %} + +{% block browser_title %}{% blocktrans %}Edit excuse type{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Edit excuse type{% endblocktrans %}{% endblock %} + +{% block content %} + + <form method="post"> + {% csrf_token %} + {% form form=form %}{% endform %} + {% include "core/partials/save_button.html" %} + </form> + +{% endblock %} diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html new file mode 100644 index 0000000000000000000000000000000000000000..2be1f28c96e70f35e63fe4f5cefb50c232e38e0a --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html @@ -0,0 +1,20 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} + +{% load i18n %} +{% load render_table from django_tables2 %} + +{% block browser_title %}{% blocktrans %}Excuse types{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Excuse types{% endblocktrans %}{% endblock %} + +{% block content %} + {% include "alsijil/excuse_type/warning.html" %} + + <a class="btn green waves-effect waves-light" href="{% url 'create_excuse_type' %}"> + <i class="material-icons left">add</i> + {% trans "Create excuse type" %} + </a> + + {% render_table table %} +{% endblock %} diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html new file mode 100644 index 0000000000000000000000000000000000000000..d90d2e8205b1c91c18e74e02654fde3daebc4971 --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html @@ -0,0 +1,10 @@ +{% load i18n %} +<div class="alert warning"> + <p> + <i class="material-icons left">warning</i> + {% blocktrans %} + This function should only be used to define alternatives to the default excuse which also will be counted extra. + Don't use this to create a default excuse or if you don't divide between different types of excuse. + {% endblocktrans %} + </p> +</div> diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py index 4406a06852ae2489eaf5b84c66a28098d91f0010..89ab0ffe5f47c8cfebb015a6f76e597af4dd11dd 100644 --- a/aleksis/apps/alsijil/urls.py +++ b/aleksis/apps/alsijil/urls.py @@ -41,4 +41,20 @@ urlpatterns = [ views.delete_personal_note_filter, name="delete_personal_note_filter", ), + path("excuse_types/", views.ExcuseTypeListView.as_view(), name="excuse_types"), + path( + "excuse_types/create/", + views.ExcuseTypeCreateView.as_view(), + name="create_excuse_type", + ), + path( + "excuse_types/<int:pk>/edit/", + views.ExcuseTypeEditView.as_view(), + name="edit_excuse_type", + ), + path( + "excuse_types/<int:pk>/delete/", + views.ExcuseTypeDeleteView.as_view(), + name="delete_excuse_type", + ), ] diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 8fa58f62a8fa267c92caa35b0de30fa90ed0ff8b..25868ba0dff775804e21038a4e6547353cffc2c2 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -5,27 +5,31 @@ from django.core.exceptions import PermissionDenied from django.db.models import Count, Exists, F, OuterRef, Q, Subquery, Sum from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect, render -from django.urls import reverse +from django.urls import reverse, reverse_lazy from django.utils.translation import ugettext as _ from calendarweek import CalendarWeek -from django_tables2 import RequestConfig +from django_tables2 import RequestConfig, SingleTableView +from reversion.views import RevisionMixin +from rules.contrib.views import PermissionRequiredMixin 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.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView from aleksis.core.models import Group, Person, SchoolTerm from aleksis.core.util import messages from .forms import ( + ExcuseTypeForm, LessonDocumentationForm, PersonalNoteFilterForm, PersonalNoteFormSet, RegisterAbsenceForm, SelectForm, ) -from .models import LessonDocumentation, PersonalNoteFilter -from .tables import PersonalNoteFilterTable +from .models import ExcuseType, LessonDocumentation, PersonalNoteFilter +from .tables import ExcuseTypeTable, PersonalNoteFilterTable def lesson( @@ -413,3 +417,44 @@ def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse: context["personal_note_filter"] = personal_note_filter return redirect("list_personal_note_filters") + + +class ExcuseTypeListView(SingleTableView, PermissionRequiredMixin): + """Table of all excuse types.""" + + model = ExcuseType + table_class = ExcuseTypeTable + permission_required = "core.view_excusetype" + template_name = "alsijil/excuse_type/list.html" + + +class ExcuseTypeCreateView(AdvancedCreateView, PermissionRequiredMixin): + """Create view for excuse types.""" + + model = ExcuseType + form_class = ExcuseTypeForm + permission_required = "core.create_excusetype" + template_name = "alsijil/excuse_type/create.html" + success_url = reverse_lazy("excuse_types") + success_message = _("The excuse type has been created.") + + +class ExcuseTypeEditView(AdvancedEditView, PermissionRequiredMixin): + """Edit view for excuse types.""" + + model = ExcuseType + form_class = ExcuseTypeForm + permission_required = "core.edit_excusetype" + template_name = "alsijil/excuse_type/edit.html" + success_url = reverse_lazy("excuse_types") + success_message = _("The excuse type has been saved.") + + +class ExcuseTypeDeleteView(AdvancedDeleteView, PermissionRequiredMixin, RevisionMixin): + """Delete view for excuse types""" + + model = ExcuseType + permission_required = "core.delete_excusetype" + template_name = "core/pages/delete.html" + success_url = reverse_lazy("excuse_types") + success_message = _("The excuse type has been deleted.")