diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9f27536f909672ac526095117dd0aecb15d984f9..8ab6d80eebe0647d1bf5d291af9e6cf540a36ea6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,8 @@ Fixed * Register absence form wasn't accessible without direct access to class register. * Printing the full group register failed when a person had no personal notes. * Data checks reported all Lesson Documentations as being during Holidays if there was no Holiday object. +* Students were displayed multiple times in class register views. +* Absences were counted multiple times in some class register views. * Group owners couldn't create new seating plans. `2.1`_ - 2022-06-25 diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py index 5b0e5ac4b1337dfdc44c97470c36cd954fc7b915..b53f87f997b9f4b62336ef594fcc2676cc00a983 100644 --- a/aleksis/apps/alsijil/model_extensions.py +++ b/aleksis/apps/alsijil/model_extensions.py @@ -434,6 +434,7 @@ def generate_person_list_with_class_register_statistics( "filtered_personal_notes", filter=Q(filtered_personal_notes__absent=True) & ~Q(filtered_personal_notes__excuse_type__count_as_absent=False), + distinct=True, ), excused=Count( "filtered_personal_notes", @@ -442,6 +443,7 @@ def generate_person_list_with_class_register_statistics( filtered_personal_notes__excused=True, ) & ~Q(filtered_personal_notes__excuse_type__count_as_absent=False), + distinct=True, ), excused_without_excuse_type=Count( "filtered_personal_notes", @@ -450,15 +452,16 @@ def generate_person_list_with_class_register_statistics( filtered_personal_notes__excused=True, filtered_personal_notes__excuse_type__isnull=True, ), + distinct=True, ), unexcused=Count( "filtered_personal_notes", filter=Q(filtered_personal_notes__absent=True, filtered_personal_notes__excused=False), + distinct=True, ), tardiness=Sum("filtered_personal_notes__late"), tardiness_count=Count( - "filtered_personal_notes", - filter=Q(filtered_personal_notes__late__gt=0), + "filtered_personal_notes", filter=Q(filtered_personal_notes__late__gt=0), distinct=True ), ) diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index dc88dea6108ddc208142bf5b510f72f1563dbd47..68833a4d5dd8814a58c3bf6cae6b1c2e2c7af701 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -240,8 +240,10 @@ def register_object( else: persons = Person.objects.all() - persons_qs = register_object.get_personal_notes(persons, wanted_week).filter( - person__member_of__in=request.user.person.owner_of.all() + persons_qs = ( + register_object.get_personal_notes(persons, wanted_week) + .filter(person__member_of__in=request.user.person.owner_of.all()) + .distinct() ) # Annotate group roles @@ -476,12 +478,16 @@ def week_view( if not request.user.has_perm("alsijil.view_week_personalnote_rule", instance): persons_qs = persons_qs.filter(pk=request.user.person.pk) elif group: - persons_qs = persons_qs.filter(member_of=group).filter( - member_of__in=request.user.person.owner_of.all() + persons_qs = ( + persons_qs.filter(member_of=group) + .filter(member_of__in=request.user.person.owner_of.all()) + .distinct() ) else: - persons_qs = persons_qs.filter(member_of__in=groups).filter( - member_of__in=request.user.person.owner_of.all() + persons_qs = ( + persons_qs.filter(member_of__in=groups) + .filter(member_of__in=request.user.person.owner_of.all()) + .distinct() ) # Prefetch object permissions for persons and groups the persons are members of @@ -792,12 +798,16 @@ def my_students(request: HttpRequest) -> HttpResponse: new_groups = [] for group in relevant_groups: - persons = group.generate_person_list_with_class_register_statistics( - group.members.prefetch_related( - "primary_group__owners", - Prefetch("member_of", queryset=relevant_groups, to_attr="member_of_prefetched"), + persons = ( + group.generate_person_list_with_class_register_statistics( + group.members.prefetch_related( + "primary_group__owners", + Prefetch("member_of", queryset=relevant_groups, to_attr="member_of_prefetched"), + ) ) - ).filter(member_of__in=request.user.person.owner_of.all()) + .filter(member_of__in=request.user.person.owner_of.all()) + .distinct() + ) persons_for_group = [] for person in persons: person.set_object_permission_checker(checker) @@ -830,10 +840,10 @@ class StudentsList(PermissionRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["group"] = self.object - context[ - "persons" - ] = self.object.generate_person_list_with_class_register_statistics().filter( - member_of__in=self.request.user.person.owner_of.all() + context["persons"] = ( + self.object.generate_person_list_with_class_register_statistics() + .filter(member_of__in=self.request.user.person.owner_of.all()) + .distinct() ) context["extra_marks"] = ExtraMark.objects.all() context["excuse_types"] = ExcuseType.objects.filter(count_as_absent=True) diff --git a/pyproject.toml b/pyproject.toml index 1381bc6d33e3ef546a6555d1e8695cae267f33d9..eb3cff73affb6750005381f2b2f03d818f1c089f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ secondary = true [tool.poetry.dependencies] python = "^3.9" -aleksis-core = "^2.7" +aleksis-core = "^2.11" aleksis-app-chronos = "^2.2" aleksis-app-stoelindeling = { version = "^1.0", optional = true } diff --git a/tox.ini b/tox.ini index 749e0606f4f02fcbd1649627219b15850cbc0a90..78e09567e193b72a299dfb3f776499420ecc04ec 100644 --- a/tox.ini +++ b/tox.ini @@ -10,7 +10,7 @@ skip_install = true envdir = {toxworkdir}/globalenv commands_pre = poetry install - poetry run aleksis-admin yarn install + poetry run aleksis-admin webpack_bundle poetry run aleksis-admin collectstatic --no-input commands = poetry run pytest --cov=. {posargs} aleksis/