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

Add rules and permissions for some views

parent 40d877cc
No related branches found
No related tags found
1 merge request!49Resolve "Add rules and permissions"
Pipeline #2689 passed
......@@ -81,3 +81,12 @@ class PersonalNoteFilter(ExtensibleModel):
verbose_name = _("Personal note filter")
verbose_name_plural = _("Personal note filters")
ordering = ["identifier"]
class AlsijilGlobalPermissions(ExtensibleModel):
class Meta:
managed = False
permissions = (
("view_week", _("Can view week overview")),
("register_absence", _("Can register absence")),
("list_personal_note_filters", _("Can list all personal note filters")),
)
from rules import add_perm
from aleksis.core.util.predicates import (
has_any_object,
has_global_perm,
has_object_perm,
has_person,
)
from .util.predicates import has_lesson_perm, has_week_perm
# View lesson
view_lesson_predicate = has_person & (
has_global_perm("chronos.view_lesson_period") | has_lesson_perm("chronos.view_lesson_period")
)
add_perm("alsijil.view_lesson", view_lesson_predicate)
# View week overview
view_week_predicate = has_person & (
has_global_perm("alsijil.view_week") | has_week_perm("alsijil")
)
add_perm("alsijil.view_week", view_week_predicate)
# Register absence
register_absence_predicate = has_person & (
has_global_perm("alsijil.register_absence")
)
add_perm("alsijil.register_absence", register_absence_predicate)
# List all personal note filters
list_personal_note_filters_predicate = has_person & has_global_perm("alsijil.list_personal_note_filters")
add_perm("alsijil.list_personal_note_filters", list_personal_note_filters_predicate)
# Edit personal note filter
edit_personal_note_filter_predicate = has_person & (
has_global_perm("alsijil.change_personal_note_filter")
| has_object_perm("alsijil.change_personal_note_filter")
)
add_perm("alsijil.edit_personal_note_filter", edit_personal_note_filter_predicate)
# Delete personal note filter
delete_personal_note_filter_predicate = has_person & (
has_global_perm("alsijil.delete_personal_note_filter")
| has_object_perm("alsijil.delete_personal_note_filter")
)
add_perm("alsijil.delete_personal_note_filter", delete_personal_note_filter_predicate)
from typing import Optional
from django.db.models import Count, Exists, OuterRef, Q, Sum
from django.http import HttpRequest, HttpResponseNotFound
from django.shortcuts import get_object_or_404
from calendarweek import CalendarWeek
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 ..models import LessonDocumentation
def get_lesson_period_by_pk(
request: HttpRequest,
year: Optional[int] = None,
week: Optional[int] = None,
period_id: Optional[int] = None,
):
if 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"):
if request.user.person.lessons_as_teacher.exists():
lesson_period = LessonPeriod.objects.at_time().filter_teacher(request.user.person).first()
else:
lesson_period = LessonPeriod.objects.at_time().filter_participant(request.user.person).first()
wanted_week = CalendarWeek()
else:
lesson_period = wanted_week = None
return lesson_period, wanted_week
def get_lesson_periods_by_pk(
request: HttpRequest,
year: Optional[int] = None,
week: Optional[int] = None,
type_: Optional[str] = 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_:
instance = 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"):
instance = 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
return lesson_periods, wanted_week, type_, instance
\ No newline at end of file
from django.contrib.auth.models import User
from rules import predicate
from aleksis.core.models import Group, Person
from aleksis.core.util.predicates import check_object_permission
def has_lesson_perm(perm: str):
"""Build predicate which checks whether the user is allowed to access the requested lesson notes."""
name = f"has_lesson_perm:{perm}"
@predicate(name)
def fn(user: User, obj: tuple) -> bool:
if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))):
return True
return check_object_permission(user, perm, obj)
return fn
@predicate
def has_week_perm(perm: str):
"""Build predicate which checks whether the user is allowed to access the week overview."""
name = f"has_week_perm:{perm}"
@predicate(name)
def fn(user: User, obj: tuple) -> bool:
if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))):
return True
return check_object_permission(user, perm, obj)
return fn
......@@ -12,11 +12,12 @@ from django.utils.translation import ugettext as _
from calendarweek import CalendarWeek
from django_tables2 import RequestConfig
from rules.contrib.views import permission_required
from aleksis.apps.chronos.models import LessonPeriod
from aleksis.core.models import Group, Person, SchoolYear
from aleksis.core.util import messages
from aleksis.core.util.core_helpers import objectgetter_optional
from .forms import (
LessonDocumentationForm,
PersonalNoteFilterForm,
......@@ -26,8 +27,10 @@ from .forms import (
)
from .models import LessonDocumentation, PersonalNoteFilter
from .tables import PersonalNoteFilterTable
from .util.alsijil_helpers import get_lesson_period_by_pk, get_lesson_periods_by_pk
@permission_required("alsijil.view_lesson", fn=get_lesson_period_by_pk)
def lesson(
request: HttpRequest,
year: Optional[int] = None,
......@@ -36,15 +39,9 @@ def lesson(
) -> HttpResponse:
context = {}
if year and week and period_id:
# Get a specific lesson period if provided in URL
lesson_period = LessonPeriod.objects.get(pk=period_id)
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()
wanted_week = CalendarWeek()
lesson_period, wanted_week = get_lesson_period_by_pk(request, year, week, period_id)
if not (year and week and period_id):
if lesson_period:
return redirect(
"lesson_by_week_and_period", wanted_week.year, wanted_week.week, lesson_period.pk,
......@@ -108,46 +105,13 @@ def lesson(
return render(request, "alsijil/lesson.html", context)
@permission_required("alsijil.view_week", fn=get_lesson_periods_by_pk)
def week_view(
request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, type_: Optional[str] = None, id_: Optional[int] = None
) -> HttpResponse:
context = {}
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)
group = None
if type_ and id_:
instance = get_el_by_pk(request, type_, id_)
if isinstance(instance, HttpResponseNotFound):
return HttpResponseNotFound()
type_ = TimetableType.from_string(type_)
if type_ == TimetableType.GROUP:
group = instance
lesson_periods = lesson_periods.filter_from_type(type_, instance)
elif hasattr(request, "user") and hasattr(request.user, "person"):
instance = 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
lesson_periods, wanted_week, type_, instance = get_lesson_periods_by_pk(request, year, week, type_, id_)
# Add a form to filter the view
if type_:
......@@ -164,6 +128,11 @@ def week_view(
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 type_ == TimetableType.GROUP:
group = instance
else:
group = None
if lesson_periods:
# Aggregate all personal notes for this group and week
lesson_periods_pk = lesson_periods.values_list("pk", flat=True)
......@@ -226,6 +195,7 @@ def week_view(
return render(request, "alsijil/week_view.html", context)
@permission_required("alsijil.full_register_group", fn=objectgetter_optional(Group, None, False))
def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
context = {}
......@@ -293,6 +263,7 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
return render(request, "alsijil/print/full_register.html", context)
@permission_required("alsijil.register_absence")
def register_absence(request: HttpRequest) -> HttpResponse:
context = {}
......@@ -324,6 +295,7 @@ def register_absence(request: HttpRequest) -> HttpResponse:
return render(request, "alsijil/register_absence.html", context)
@permission_required("alsijil.list_personal_note_filters")
def list_personal_note_filters(request: HttpRequest) -> HttpResponse:
context = {}
......@@ -338,6 +310,7 @@ def list_personal_note_filters(request: HttpRequest) -> HttpResponse:
return render(request, "alsijil/personal_note_filters.html", context)
@permission_required("alsijil.edit_personal_note_filter", fn=objectgetter_optional(PersonalNoteFilter, None, False))
def edit_personal_note_filter(request: HttpRequest, id: Optional["int"] = None) -> HttpResponse:
context = {}
......@@ -362,6 +335,7 @@ def edit_personal_note_filter(request: HttpRequest, id: Optional["int"] = None)
return render(request, "alsijil/manage_personal_note_filter.html", context)
@permission_required("alsijil.delete_personal_note_filter", fn=objectgetter_optional(PersonalNoteFilter, None, False))
def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse:
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