Skip to content
Snippets Groups Projects
Verified Commit f122b128 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add overview of all register objects for coordinators ("All lessons")

parent da7996a8
No related branches found
No related tags found
1 merge request!152Overview of all register objects
Pipeline #6139 passed
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, Sequence
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Count, Q from django.db.models import Count, Q
from django.http import HttpRequest
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
...@@ -278,41 +280,35 @@ class FilterRegisterObjectForm(forms.Form): ...@@ -278,41 +280,35 @@ class FilterRegisterObjectForm(forms.Form):
"date_end": date_end, "date_end": date_end,
} }
def __init__(self, request, for_person=True, *args, **kwargs): def __init__(
self,
request: HttpRequest,
*args,
for_person: bool = True,
groups: Optional[Sequence[Group]] = None,
**kwargs
):
self.request = request self.request = request
person = self.request.user.person person = self.request.user.person
# Fill in initial data
kwargs["initial"] = self.get_initial() kwargs["initial"] = self.get_initial()
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# Build querysets
self.fields["school_term"].queryset = SchoolTerm.objects.all() self.fields["school_term"].queryset = SchoolTerm.objects.all()
# Filter selectable groups by permissions if not groups and for_person:
group_qs = Group.objects.all() groups = Group.objects.filter(
if for_person:
group_qs = group_qs.filter(
Q(lessons__teachers=person) Q(lessons__teachers=person)
| Q(lessons__lesson_periods__substitutions__teachers=person) | Q(lessons__lesson_periods__substitutions__teachers=person)
| Q(events__teachers=person) | Q(events__teachers=person)
| Q(extra_lessons__teachers=person) | Q(extra_lessons__teachers=person)
) )
elif not check_global_permission(self.request.user, "alsijil.view_full_register"): elif not for_person:
group_qs = group_qs.union( groups = Group.objects.all()
group_qs.filter( self.fields["group"].queryset = groups
pk__in=get_objects_for_user(
self.request.user, "core.view_full_register_group", Group
).values_list("pk", flat=True)
)
)
# Flatten query by filtering groups by pk
groups_flat = Group.objects.filter(pk__in=list(group_qs.values_list("pk", flat=True)))
self.fields["group"].queryset = groups_flat
# Filter subjects by selectable groups # Filter subjects by selectable groups
subject_qs = Subject.objects.filter( subject_qs = Subject.objects.filter(
Q(lessons__groups__in=groups_flat) | Q(extra_lessons__groups__in=groups_flat) Q(lessons__groups__in=groups) | Q(extra_lessons__groups__in=groups)
).distinct() ).distinct()
self.fields["subject"].queryset = subject_qs self.fields["subject"].queryset = subject_qs
...@@ -78,6 +78,17 @@ MENUS = { ...@@ -78,6 +78,17 @@ MENUS = {
), ),
], ],
}, },
{
"name": _("All lessons"),
"url": "all_register_objects",
"icon": "list",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"alsijil.view_register_objects_list",
),
],
},
{ {
"name": _("Excuse types"), "name": _("Excuse types"),
"url": "excuse_types", "url": "excuse_types",
......
from rules import add_perm from rules import add_perm
from aleksis.core.models import Group
from aleksis.core.util.predicates import ( from aleksis.core.util.predicates import (
has_any_object,
has_global_perm, has_global_perm,
has_object_perm, has_object_perm,
has_person, has_person,
...@@ -273,3 +275,9 @@ delete_group_role_assignment_predicate = ( ...@@ -273,3 +275,9 @@ delete_group_role_assignment_predicate = (
has_global_perm("alsjil.assign_grouprole") | is_group_role_assignment_group_owner has_global_perm("alsjil.assign_grouprole") | is_group_role_assignment_group_owner
) )
add_perm("alsijil.delete_grouproleassignment", delete_group_role_assignment_predicate) add_perm("alsijil.delete_grouproleassignment", delete_group_role_assignment_predicate)
view_register_objects_list_predicate = has_person & (
has_any_object("core.view_full_register_group", Group)
| has_global_perm("core.view_full_register")
)
add_perm("alsijil.view_register_objects_list", view_register_objects_list_predicate)
{# -*- engine:django -*- #}
{% extends "core/base.html" %}
{% load i18n rules static django_tables2 material_form %}
{% block browser_title %}{% blocktrans %}All lessons{% endblocktrans %}{% endblock %}
{% block page_title %}
{% blocktrans %}All lessons{% endblocktrans %}
{% endblock %}
{% block extra_head %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/>
{% endblock %}
{% block content %}
<h5>{% trans "Lesson filter" %}</h5>
<form action="" method="get">
{% form form=filter_form %}{% endform %}
<button type="submit" class="btn waves-effect waves-light">
<i class="material-icons left">refresh</i>
{% trans "Update filters" %}
</button>
</form>
<h5>{% trans "Lesson table" %}</h5>
{% if table %}
{% render_table table %}
{% endif %}
{% endblock %}
\ No newline at end of file
...@@ -100,4 +100,5 @@ urlpatterns = [ ...@@ -100,4 +100,5 @@ urlpatterns = [
views.AssignGroupRoleMultipleView.as_view(), views.AssignGroupRoleMultipleView.as_view(),
name="assign_group_role_multiple", name="assign_group_role_multiple",
), ),
path("all/", views.AllRegisterObjectsView.as_view(), name="all_register_objects"),
] ]
from operator import itemgetter from operator import itemgetter
from typing import List, Optional, Union from typing import Any, Dict, List, Optional, Union
from django.db.models.expressions import Exists, OuterRef from django.db.models.expressions import Exists, OuterRef
from django.db.models.query import Prefetch, QuerySet from django.db.models.query import Prefetch, QuerySet
...@@ -112,7 +112,7 @@ def register_objects_sorter(register_object: Union[LessonPeriod, Event, ExtraLes ...@@ -112,7 +112,7 @@ def register_objects_sorter(register_object: Union[LessonPeriod, Event, ExtraLes
return 0 return 0
def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]: def generate_list_of_all_register_objects(filter_dict: Dict[str, Any]) -> List[dict]:
# Get data for filtering # Get data for filtering
initial_filter_data = FilterRegisterObjectForm.get_initial() initial_filter_data = FilterRegisterObjectForm.get_initial()
# Always force a selected school term so that queries won't get to big # Always force a selected school term so that queries won't get to big
...@@ -120,6 +120,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]: ...@@ -120,6 +120,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
filter_person = filter_dict.get("person") filter_person = filter_dict.get("person")
should_have_documentation = filter_dict.get("has_documentation") should_have_documentation = filter_dict.get("has_documentation")
filter_group = filter_dict.get("group") filter_group = filter_dict.get("group")
filter_groups = filter_dict.get("groups")
filter_subject = filter_dict.get("subject") filter_subject = filter_dict.get("subject")
filter_date_start = filter_dict.get("date_start", initial_filter_data.get("date_start")) filter_date_start = filter_dict.get("date_start", initial_filter_data.get("date_start"))
filter_date_end = filter_dict.get("date_end", initial_filter_data.get("date_end")) filter_date_end = filter_dict.get("date_end", initial_filter_data.get("date_end"))
...@@ -166,6 +167,10 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]: ...@@ -166,6 +167,10 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
lesson_periods = lesson_periods.filter_group(filter_group) lesson_periods = lesson_periods.filter_group(filter_group)
events = events.filter_group(filter_group) events = events.filter_group(filter_group)
extra_lessons = extra_lessons.filter_group(filter_group) extra_lessons = extra_lessons.filter_group(filter_group)
if filter_groups:
lesson_periods = lesson_periods.filter_groups(filter_groups)
events = events.filter_groups(filter_groups)
extra_lessons = extra_lessons.filter_groups(filter_groups)
if filter_subject: if filter_subject:
lesson_periods = lesson_periods.filter( lesson_periods = lesson_periods.filter(
Q(lesson__subject=filter_subject) | Q(substitutions__subject=filter_subject) Q(lesson__subject=filter_subject) | Q(substitutions__subject=filter_subject)
...@@ -293,7 +298,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]: ...@@ -293,7 +298,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
f"{date_format(register_object.date_start)}" f"{date_format(register_object.date_start)}"
f"{date_format(register_object.date_end)}" f"{date_format(register_object.date_end)}"
) )
day_sort = (register_object.date_start,) day_sort = register_object.date_start
period = ( period = (
f"{register_object.period_from.period}.–{register_object.period_to.period}." f"{register_object.period_from.period}.–{register_object.period_to.period}."
) )
......
...@@ -13,12 +13,14 @@ from django.urls import reverse, reverse_lazy ...@@ -13,12 +13,14 @@ from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views import View
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.generic import DetailView from django.views.generic import DetailView
import reversion import reversion
from calendarweek import CalendarWeek from calendarweek import CalendarWeek
from django_tables2 import RequestConfig, SingleTableView from django_tables2 import RequestConfig, SingleTableView
from guardian.shortcuts import get_objects_for_user
from reversion.views import RevisionMixin from reversion.views import RevisionMixin
from rules.contrib.views import PermissionRequiredMixin, permission_required from rules.contrib.views import PermissionRequiredMixin, permission_required
...@@ -35,6 +37,7 @@ from aleksis.core.mixins import ( ...@@ -35,6 +37,7 @@ from aleksis.core.mixins import (
from aleksis.core.models import Group, Person, SchoolTerm from aleksis.core.models import Group, Person, SchoolTerm
from aleksis.core.util import messages from aleksis.core.util import messages
from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional
from aleksis.core.util.predicates import check_global_permission
from .forms import ( from .forms import (
AssignGroupRoleForm, AssignGroupRoleForm,
...@@ -899,10 +902,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp ...@@ -899,10 +902,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
context["extra_marks"] = extra_marks context["extra_marks"] = extra_marks
# Build filter with own form and logic as django-filter can't work with different models # Build filter with own form and logic as django-filter can't work with different models
filter_form = FilterRegisterObjectForm(request, True, request.GET or None) filter_form = FilterRegisterObjectForm(request, request.GET or None, for_person=True)
filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {} filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {}
filter_dict["person"] = person filter_dict["person"] = person
context["filter_form"] = filter_form context["filter_form"] = filter_form
register_objects = generate_list_of_all_register_objects(filter_dict) register_objects = generate_list_of_all_register_objects(filter_dict)
if register_objects: if register_objects:
table = RegisterObjectTable(register_objects) table = RegisterObjectTable(register_objects)
...@@ -1246,3 +1250,32 @@ class GroupRoleAssignmentDeleteView( ...@@ -1246,3 +1250,32 @@ class GroupRoleAssignmentDeleteView(
def get_success_url(self) -> str: def get_success_url(self) -> str:
pk = self.object.groups.first().pk pk = self.object.groups.first().pk
return reverse("assigned_group_roles", args=[pk]) return reverse("assigned_group_roles", args=[pk])
class AllRegisterObjectsView(PermissionRequiredMixin, View):
permission_required = "alsijil.view_register_objects_list"
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
context = {}
# Filter selectable groups by permissions
groups = Group.objects.all()
if not check_global_permission(request.user, "alsijil.view_full_register"):
allowed_groups = get_objects_for_user(
self.request.user, "core.view_full_register_group", Group
).values_list("pk", flat=True)
groups = groups.filter(Q(parent_groups__in=allowed_groups) | Q(pk__in=allowed_groups))
# Build filter with own form and logic as django-filter can't work with different models
filter_form = FilterRegisterObjectForm(
request, request.GET or None, for_person=False, groups=groups
)
filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {}
filter_dict["groups"] = groups
context["filter_form"] = filter_form
register_objects = generate_list_of_all_register_objects(filter_dict)
if register_objects:
table = RegisterObjectTable(register_objects)
RequestConfig(request,).configure(table) # paginate={"per_page": 100}
context["table"] = table
return render(request, "alsijil/class_register/all_objects.html", 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