Skip to content
Snippets Groups Projects
Commit e65b4cb2 authored by Hangzhi Yu's avatar Hangzhi Yu
Browse files

Add some more rules&permissions

parent 6e338635
No related branches found
No related tags found
1 merge request!49Resolve "Add rules and permissions"
Pipeline #2735 passed
from datetime import date from datetime import date
from django.db.models import Exists, F, OuterRef from django.db.models import Exists, F, OuterRef, QuerySet
from django.utils.translation import ugettext as _
from calendarweek import CalendarWeek from calendarweek import CalendarWeek
...@@ -57,7 +58,7 @@ def mark_absent( ...@@ -57,7 +58,7 @@ def mark_absent(
@LessonPeriod.method @LessonPeriod.method
def get_personal_notes(self, wanted_week: CalendarWeek): def get_personal_notes(self, persons: QuerySet, 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, Returns all linked `PersonalNote` objects, filtered by the given weeek,
...@@ -71,7 +72,7 @@ def get_personal_notes(self, wanted_week: CalendarWeek): ...@@ -71,7 +72,7 @@ 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 # Find all persons in the associated groups that do not yet have a personal note for this lesson
missing_persons = Person.objects.annotate( missing_persons = persons.annotate(
no_personal_notes=~Exists( no_personal_notes=~Exists(
PersonalNote.objects.filter( PersonalNote.objects.filter(
week=wanted_week.week, lesson_period=self, person__pk=OuterRef("pk") week=wanted_week.week, lesson_period=self, person__pk=OuterRef("pk")
...@@ -94,3 +95,13 @@ def get_personal_notes(self, wanted_week: CalendarWeek): ...@@ -94,3 +95,13 @@ def get_personal_notes(self, wanted_week: CalendarWeek):
return PersonalNote.objects.select_related("person").filter( return PersonalNote.objects.select_related("person").filter(
lesson_period=self, week=wanted_week.week lesson_period=self, week=wanted_week.week
) )
# Dynamically add extra permissions to Group and Person models in core, requires migration afterwards
Group.add_permission("view_week_class_register_group", _("Can view week overview of group class register"))
Group.add_permission("view_personalnote_group", _("Can view all personal notes of a group"))
Group.add_permission("edit_personalnote_group", _("Can edit all personal notes of a group"))
Group.add_permission("view_lessondocumentation_group", _("Can view all lesson documentation of a group"))
Group.add_permission("edit_lessondocumentation_group", _("Can edit all lesson documentation of a group"))
Group.add_permission("view_full_register_group", _("Can view full register of a group"))
Group.add_permission("register_absence_group", _("Can register a absence for all members of a group"))
Person.add_permission("register_absence_person", _("Can register a absence for a person"))
...@@ -5,31 +5,96 @@ from aleksis.core.util.predicates import ( ...@@ -5,31 +5,96 @@ from aleksis.core.util.predicates import (
has_global_perm, has_global_perm,
has_object_perm, has_object_perm,
has_person, has_person,
is_current_person,
)
from .util.predicates import (
is_lesson_teacher,
is_lesson_participant,
is_lesson_parent_group_owner,
has_lesson_group_object_perm,
is_group_member,
is_group_owner,
has_person_group_object_perm,
is_person_group_owner,
) )
from .util.predicates import has_lesson_perm, has_week_perm
# View lesson # View lesson
view_lesson_predicate = has_person & ( view_lesson_predicate = has_person & (
has_global_perm("chronos.view_lesson_period") | has_lesson_perm("chronos.view_lesson_period") has_global_perm("alsijil.view_lesson") | is_lesson_teacher | is_lesson_participant | is_lesson_parent_group_owner | has_lesson_group_object_perm("alsijil.view_lesson")
) )
add_perm("alsijil.view_lesson", view_lesson_predicate) add_perm("alsijil.view_lesson", view_lesson_predicate)
# View lesson personal notes
view_lesson_personal_notes_predicate = has_person & (
has_global_perm("alsijil.view_personalnote") |
has_lesson_group_object_perm("core.view_personalnote_group") |
is_lesson_teacher |
is_lesson_parent_group_owner
)
add_perm("alsijil.view_lesson_personalnote", view_lesson_personal_notes_predicate)
# Edit lesson personal notes
edit_lesson_personal_notes_predicate = has_person & (
has_global_perm("alsijil.change_personalnote") |
has_lesson_group_object_perm("core.edit_personalnote_group") |
is_lesson_teacher
)
add_perm("alsijil.edit_personalnote", edit_lesson_personal_notes_predicate)
# View lesson documentation
view_lesson_documentation_predicate = has_person & (
has_global_perm("alsijil.view_lessondocumentation") |
has_lesson_group_object_perm("core.view_lessondocumentation_group") |
is_lesson_teacher |
is_lesson_parent_group_owner |
is_lesson_participant
)
add_perm("alsijil.view_lessondocumentation", view_lesson_documentation_predicate)
# Edit lesson documentation
edit_lesson_documentation_predicate = has_person & (
has_global_perm("alsijil.change_lessondocumentation") |
has_lesson_group_object_perm("core.edit_lessondocumentation_group") |
is_lesson_teacher
)
add_perm("alsijil.edit_lessondocumentation", edit_lesson_documentation_predicate)
# View week overview # View week overview
view_week_predicate = has_person & ( view_week_predicate = has_person & (
has_global_perm("alsijil.view_week") | has_week_perm("alsijil") has_global_perm("alsijil.view_week") | has_object_perm("core.view_week_class_register_group") | is_group_member | is_group_owner | is_current_person
) )
add_perm("alsijil.view_week", view_week_predicate) add_perm("alsijil.view_week", view_week_predicate)
# View week personal notes
view_week_personal_notes_predicate = has_person & (
has_global_perm("alsijil.view_personalnote") |
has_object_perm("alsijil.view_personalnote") |
is_group_owner
)
add_perm("alsijil.view_week_personalnote", view_week_personal_notes_predicate)
# Register absence # Register absence
register_absence_predicate = has_person & ( register_absence_predicate = has_person & (
has_global_perm("alsijil.register_absence") has_global_perm("alsijil.register_absence") |
has_person_group_object_perm("core.register_absence_group") |
has_global_perm("core.register_absence_person") |
is_person_group_owner
) )
add_perm("alsijil.register_absence", register_absence_predicate) add_perm("alsijil.register_absence", register_absence_predicate)
# List all personal note filters # View full register for group
list_personal_note_filters_predicate = has_person & has_global_perm("alsijil.list_personal_note_filters") view_full_register_predicate = has_person & (
add_perm("alsijil.list_personal_note_filters", list_personal_note_filters_predicate) has_global_perm("alsijil.view_full_register") |
has_object_perm("core.view_full_register_group") |
is_group_owner
)
add_perm("alsijil.view_full_register", view_full_register_predicate)
# View all personal note filters
list_personal_note_filters_predicate = has_person & has_global_perm("alsijil.view_personal_note_filter")
add_perm("alsijil.view_personal_note_filters", list_personal_note_filters_predicate)
# Edit personal note filter # Edit personal note filter
edit_personal_note_filter_predicate = has_person & ( edit_personal_note_filter_predicate = has_person & (
......
{# -*- engine:django -*- #} {# -*- engine:django -*- #}
{% extends "core/base.html" %} {% extends "core/base.html" %}
{% load material_form i18n static %} {% load material_form i18n static rules %}
{% block browser_title %}{% blocktrans %}Lesson{% endblocktrans %}{% endblock %} {% block browser_title %}{% blocktrans %}Lesson{% endblocktrans %}{% endblock %}
...@@ -34,9 +34,33 @@ ...@@ -34,9 +34,33 @@
{% blocktrans %}Lesson documentation{% endblocktrans %} {% blocktrans %}Lesson documentation{% endblocktrans %}
</div> </div>
{% csrf_token %} {% csrf_token %}
{% form form=lesson_documentation_form %}{% endform %} {% has_perm "alsijil.view_lessondocumentation" user lesson_period as can_view_lesson_documentation %}
{% has_perm "alsijil.edit_lessondocumentation" user lesson_period as can_edit_lesson_documentation %}
{% if can_edit_lesson_documentation %}
{% form form=lesson_documentation_form %}{% endform %}
{% elif can_view_lesson_documentation %}
<table>
<tr>
<th>
{% trans "Lesson topic" %}
</th>
<td>
{{ lesson_documentation.topic }}
</td>
</tr>
<tr>
<th>
{% trans "Homework" %}
</th>
<td>
{{ lesson_documentation.homework }}
</td>
</tr>
</table>
{% endif %}
</div> </div>
</div> </div>
{% if can_view_lesson_documentation %}
<div class="col s4"> <div class="col s4">
<div class="card dark-text"> <div class="card dark-text">
<span class="card-title"> <span class="card-title">
...@@ -45,12 +69,14 @@ ...@@ -45,12 +69,14 @@
{% include 'core/crud_events_ul.html' with class_ul='list-group list-group-flush' class_li='list-group-item d-flex justify-content-between align-items-center' obj=lesson_documentation %} {% include 'core/crud_events_ul.html' with class_ul='list-group list-group-flush' class_li='list-group-item d-flex justify-content-between align-items-center' obj=lesson_documentation %}
</div> </div>
</div> </div>
{% endif %}
</div> </div>
<div class="card dark-text"> <div class="card dark-text">
<span class="card-title"> <span class="card-title">
{% blocktrans %}Personal notes{% endblocktrans %} {% blocktrans %}Personal notes{% endblocktrans %}
</span> </span>
{% has_perm "alsijil.edit_personalnote" user lesson_period as can_edit_personalnote %}
{{ personal_note_formset.management_form }} {{ personal_note_formset.management_form }}
<table class="striped responsive-table"> <table class="striped responsive-table">
...@@ -62,17 +88,29 @@ ...@@ -62,17 +88,29 @@
<th>{% blocktrans %}Remarks{% endblocktrans %}</th> <th>{% blocktrans %}Remarks{% endblocktrans %}</th>
</tr> </tr>
{% for form in personal_note_formset %} {% for form in personal_note_formset %}
{{ form.id }} {% if can_edit_personalnote %}
<tr> {{ form.id }}
<td>{{ form.person_name }}</td> <tr>
<td>{{ form.absent }}</td> <td>{{ form.person_name }}</td>
<td>{{ form.late }}</td> <td>{{ form.absent }}</td>
<td>{{ form.excused }}</td> <td>{{ form.late }}</td>
<td>{{ form.remarks }}</td> <td>{{ form.excused }}</td>
</tr> <td>{{ form.remarks }}</td>
</tr>
{% else %}
<tr>
<td>{{ form.person_name.value }}</td>
<td>{{ form.absent.value }}</td>
<td>{{ form.late.value }}</td>
<td>{{ form.excused.value }}</td>
<td>{{ form.remarks.value }}</td>
</tr>
{% endif %}
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
{% include "core/save_button.html" %} {% if can_edit_lesson_documentation or can_edit_personalnote %}
{% include "core/save_button.html" %}
{% endif %}
</form> </form>
{% endblock %} {% endblock %}
...@@ -20,54 +20,24 @@ def get_lesson_period_by_pk( ...@@ -20,54 +20,24 @@ def get_lesson_period_by_pk(
): ):
if period_id: if period_id:
lesson_period = LessonPeriod.objects.get(pk=period_id) lesson_period = LessonPeriod.objects.get(pk=period_id)
wanted_week = CalendarWeek(year=year, week=week)
elif hasattr(request, "user") and hasattr(request.user, "person"): elif hasattr(request, "user") and hasattr(request.user, "person"):
if request.user.person.lessons_as_teacher.exists(): if request.user.person.lessons_as_teacher.exists():
lesson_period = LessonPeriod.objects.at_time().filter_teacher(request.user.person).first() lesson_period = LessonPeriod.objects.at_time().filter_teacher(request.user.person).first()
else: else:
lesson_period = LessonPeriod.objects.at_time().filter_participant(request.user.person).first() lesson_period = LessonPeriod.objects.at_time().filter_participant(request.user.person).first()
wanted_week = CalendarWeek()
else: else:
lesson_period = wanted_week = None lesson_period = None
return lesson_period, wanted_week return lesson_period
def get_lesson_periods_by_pk( def get_instance_by_pk(
request: HttpRequest, request: HttpRequest,
year: Optional[int] = None, year: Optional[int] = None,
week: Optional[int] = None, week: Optional[int] = None,
type_: Optional[str] = None, type_: Optional[str] = None,
id_: Optional[int] = None, id_: Optional[int] = None,
): ):
if year and week:
wanted_week = CalendarWeek(year=year, week=week)
else:
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
)
)
).in_week(wanted_week)
if type_ and id_: if type_ and id_:
instance = get_el_by_pk(request, type_, id_) return get_el_by_pk(request, type_, id_)
if isinstance(instance, HttpResponseNotFound):
return HttpResponseNotFound()
type_ = TimetableType.from_string(type_)
lesson_periods = lesson_periods.filter_from_type(type_, instance)
elif hasattr(request, "user") and hasattr(request.user, "person"): elif hasattr(request, "user") and hasattr(request.user, "person"):
instance = request.user.person return request.user.person
if request.user.person.lessons_as_teacher.exists(): \ No newline at end of file
lesson_periods = lesson_periods.filter_teacher(request.user.person)
type_ = TimetableType.TEACHER
else:
lesson_periods = lesson_periods.filter_participant(request.user.person)
else:
lesson_periods = None
return lesson_periods, wanted_week, type_, instance
\ No newline at end of file
from typing import Union
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rules import predicate from rules import predicate
from aleksis.apps.chronos.models import LessonPeriod
from aleksis.core.models import Group, Person from aleksis.core.models import Group, Person
from aleksis.core.util.predicates import check_object_permission from aleksis.core.util.predicates import check_object_permission
def has_lesson_perm(perm: str): @predicate
"""Build predicate which checks whether the user is allowed to access the requested lesson notes.""" def is_lesson_teacher(user: User, obj: LessonPeriod) -> bool:
name = f"has_lesson_perm:{perm}" """Predicate which checks whether the person linked to the user is a teacher in the lesson linked to the given LessonPeriod."""
return user.person in obj.lesson.teachers
@predicate(name) @predicate
def fn(user: User, obj: tuple) -> bool: def is_lesson_participant(user: User, obj: LessonPeriod) -> bool:
if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))): """Predicate which checks whether the person linked to the user is a member in the groups linked to the given LessonPeriod."""
return obj.lesson.groups.filter(members=user.person).exists()
@predicate
def is_lesson_parent_group_owner(user: User, obj: LessonPeriod) -> bool:
"""Predicate which checks whether the person linked to the user is the owner of any parent groups of any groups of the given LessonPeriods lesson."""
return obj.lesson.groups.filter(parent_groups__owners=user.person).exists()
@predicate
def is_group_owner(user: User, obj: Union[Group, Person]) -> bool:
"""Predicate which checks whether the person linked to the user is the owner of the given group."""
if isinstance(obj, Group):
if obj.owners.filter(pk=user.person.pk).exists():
return True return True
return check_object_permission(user, perm, obj)
return fn return False
@predicate
def is_person_group_owner(user: User, obj: Person) -> bool:
"""Predicate which checks whether the person linked to the user is the owner of any group of the given person."""
return obj.filter(member_of__owners=user.person).exists()
@predicate @predicate
def has_week_perm(perm: str): def has_person_group_object_perm(perm: str):
"""Build predicate which checks whether the user is allowed to access the week overview.""" """Predicate which checks whether a user has a permission on any group of a person."""
name = f"has_week_perm:{perm}" name = f"has_person_group_object_perm:{perm}"
@predicate(name) @predicate(name)
def fn(user: User, obj: tuple) -> bool: def fn(user: User, obj: Person) -> bool:
if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))): for group in obj.member_of.all():
if check_object_permission(user, perm, group):
return True
return False
return fn
@predicate
def is_group_member(user: User, obj: Union[Group, Person]) -> bool:
"""Predicate which checks whether the person linked to the user is a member of the given group."""
if isinstance(obj, Group):
if obj.members.filter(pk=user.person.pk).exists():
return True return True
return check_object_permission(user, perm, obj)
return False
def has_lesson_group_object_perm(perm: str):
"""Build predicate which checks whether a user has a permission on any group of a LessonPeriod."""
name = f"has_lesson_group_object_perm:{perm}"
@predicate(name)
def fn(user: User, obj: LessonPeriod) -> bool:
for group in obj.lesson.groups.all():
if check_object_permission(user, perm, group):
return True
return False
return fn return fn
...@@ -15,7 +15,7 @@ from django_tables2 import RequestConfig ...@@ -15,7 +15,7 @@ from django_tables2 import RequestConfig
from rules.contrib.views import permission_required from rules.contrib.views import permission_required
from aleksis.apps.chronos.models import LessonPeriod from aleksis.apps.chronos.models import LessonPeriod
from aleksis.core.models import Group, Person, SchoolYear from aleksis.core.models import Group, Person
from aleksis.core.util import messages from aleksis.core.util import messages
from aleksis.core.util.core_helpers import objectgetter_optional from aleksis.core.util.core_helpers import objectgetter_optional
from .forms import ( from .forms import (
...@@ -27,7 +27,7 @@ from .forms import ( ...@@ -27,7 +27,7 @@ from .forms import (
) )
from .models import LessonDocumentation, PersonalNoteFilter from .models import LessonDocumentation, PersonalNoteFilter
from .tables import PersonalNoteFilterTable from .tables import PersonalNoteFilterTable
from .util.alsijil_helpers import get_lesson_period_by_pk, get_lesson_periods_by_pk from .util.alsijil_helpers import get_lesson_period_by_pk, get_instance_by_pk
@permission_required("alsijil.view_lesson", fn=get_lesson_period_by_pk) @permission_required("alsijil.view_lesson", fn=get_lesson_period_by_pk)
...@@ -39,7 +39,14 @@ def lesson( ...@@ -39,7 +39,14 @@ def lesson(
) -> HttpResponse: ) -> HttpResponse:
context = {} context = {}
lesson_period, wanted_week = get_lesson_period_by_pk(request, year, week, period_id) lesson_period = get_lesson_period_by_pk(request, year, week, period_id)
if period_id:
wanted_week = CalendarWeek(year=year, week=week)
elif hasattr(request, "user") and hasattr(request.user, "person"):
wanted_week = CalendarWeek()
else:
wanted_week = None
if not (year and week and period_id): if not (year and week and period_id):
if lesson_period: if lesson_period:
...@@ -77,16 +84,19 @@ def lesson( ...@@ -77,16 +84,19 @@ def lesson(
) )
# Create a formset that holds all personal notes for all persons in this lesson # Create a formset that holds all personal notes for all persons in this lesson
persons_qs = lesson_period.get_personal_notes(wanted_week) persons = Person.objects
if not request.user.has_perm("alsijil.view_lesson_personalnote", lesson_period):
persons = persons.filter(pk=request.user.pk)
persons_qs = lesson_period.get_personal_notes(persons, wanted_week)
personal_note_formset = PersonalNoteFormSet( 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(): if lesson_documentation_form.is_valid() and request.user.has_perm("alsijil.edit_lessondocumentation", lesson_period):
lesson_documentation_form.save() lesson_documentation_form.save()
if personal_note_formset.is_valid(): if personal_note_formset.is_valid() and request.user.has_perm("alsijil.edit_personalnote", lesson_period):
instances = personal_note_formset.save() instances = personal_note_formset.save()
# Iterate over personal notes and carry changed absences to following lessons # Iterate over personal notes and carry changed absences to following lessons
...@@ -105,13 +115,45 @@ def lesson( ...@@ -105,13 +115,45 @@ def lesson(
return render(request, "alsijil/lesson.html", context) return render(request, "alsijil/lesson.html", context)
@permission_required("alsijil.view_week", fn=get_lesson_periods_by_pk) @permission_required("alsijil.view_week", fn=get_instance_by_pk)
def week_view( 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: ) -> HttpResponse:
context = {} context = {}
lesson_periods, wanted_week, type_, instance = get_lesson_periods_by_pk(request, year, week, type_, id_) instance = get_instance_by_pk(request, year, week, type_, id_)
lesson_periods = LessonPeriod.objects
if type_ and id_:
if isinstance(instance, HttpResponseNotFound):
return HttpResponseNotFound()
type_ = TimetableType.from_string(type_)
lesson_periods = lesson_periods.filter_from_type(type_, instance)
elif hasattr(request, "user") and hasattr(request.user, "person"):
if request.user.person.lessons_as_teacher.exists():
lesson_periods = lesson_periods.filter_teacher(request.user.person)
type_ = TimetableType.TEACHER
else:
lesson_periods = lesson_periods.filter_participant(request.user.person)
else:
lesson_periods = None
if year and week:
wanted_week = CalendarWeek(year=year, week=week)
else:
wanted_week = CalendarWeek()
lesson_periods = lesson_periods.annotate(
has_documentation=Exists(
LessonDocumentation.objects.filter(
~Q(topic__exact=""), lesson_period=OuterRef("pk"), week=wanted_week.week
)
)
).in_week(wanted_week)
# Add a form to filter the view # Add a form to filter the view
if type_: if type_:
...@@ -136,9 +178,14 @@ def week_view( ...@@ -136,9 +178,14 @@ def week_view(
if lesson_periods: if lesson_periods:
# Aggregate all personal notes for this group and week # Aggregate all personal notes for this group and week
lesson_periods_pk = lesson_periods.values_list("pk", flat=True) lesson_periods_pk = lesson_periods.values_list("pk", flat=True)
persons = (
Person.objects.filter(is_active=True)
.filter(member_of__lessons__lesson_periods__in=lesson_periods_pk) persons = Person.objects.filter(is_active=True)
if not request.user.has_perm("alsijil.view_week_personalnote", instance):
persons = persons.filter(pk=request.user.pk)
persons = (persons.filter(member_of__lessons__lesson_periods__in=lesson_periods_pk)
.distinct() .distinct()
.prefetch_related("personal_notes") .prefetch_related("personal_notes")
.annotate( .annotate(
...@@ -195,7 +242,7 @@ def week_view( ...@@ -195,7 +242,7 @@ def week_view(
return render(request, "alsijil/week_view.html", context) return render(request, "alsijil/week_view.html", context)
@permission_required("alsijil.full_register_group", fn=objectgetter_optional(Group, None, False)) @permission_required("alsijil.view_full_register", fn=objectgetter_optional(Group, None, False))
def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
context = {} context = {}
...@@ -270,7 +317,7 @@ def register_absence(request: HttpRequest) -> HttpResponse: ...@@ -270,7 +317,7 @@ def register_absence(request: HttpRequest) -> HttpResponse:
register_absence_form = RegisterAbsenceForm(request.POST or None) register_absence_form = RegisterAbsenceForm(request.POST or None)
if request.method == "POST": if request.method == "POST":
if register_absence_form.is_valid(): if register_absence_form.is_valid() and request.user.has_perm("alsijil.register_absence", register_absence_form.cleaned_data["person"]):
# Get data from form # 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"] start_date = register_absence_form.cleaned_data["date_start"]
...@@ -295,7 +342,7 @@ def register_absence(request: HttpRequest) -> HttpResponse: ...@@ -295,7 +342,7 @@ def register_absence(request: HttpRequest) -> HttpResponse:
return render(request, "alsijil/register_absence.html", context) return render(request, "alsijil/register_absence.html", context)
@permission_required("alsijil.list_personal_note_filters") @permission_required("alsijil.view_personal_note_filters")
def list_personal_note_filters(request: HttpRequest) -> HttpResponse: def list_personal_note_filters(request: HttpRequest) -> HttpResponse:
context = {} context = {}
......
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