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

Merge branch '319-adapt-to-active-school-term' into 'master'

Resolve "Adapt to active school term"

Closes #319

See merge request !429
parents a81f3354 abadf508
No related branches found
No related tags found
1 merge request!429Resolve "Adapt to active school term"
Pipeline #193965 canceled
Showing
with 119 additions and 67 deletions
...@@ -70,7 +70,10 @@ ...@@ -70,7 +70,10 @@
</template> </template>
</infinite-scrolling-date-sorted-c-r-u-d-iterator> </infinite-scrolling-date-sorted-c-r-u-d-iterator>
<v-scale-transition> <v-scale-transition>
<absence-creation-dialog v-if="pageType === 'absences'" /> <absence-creation-dialog
v-if="pageType === 'absences'"
:absence-reasons="absenceReasons"
/>
</v-scale-transition> </v-scale-transition>
</div> </div>
</template> </template>
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
:end-date="endDate" :end-date="endDate"
:comment="comment" :comment="comment"
:absence-reason="absenceReason" :absence-reason="absenceReason"
:absence-reasons="absenceReasons"
@valid="formValid = $event" @valid="formValid = $event"
@persons="persons = $event" @persons="persons = $event"
@start-date="startDate = $event" @start-date="startDate = $event"
...@@ -121,6 +122,12 @@ export default { ...@@ -121,6 +122,12 @@ export default {
absenceReason: "", absenceReason: "",
}; };
}, },
props: {
absenceReasons: {
type: Array,
required: true,
},
},
mounted() { mounted() {
this.addPermissions(["alsijil.view_register_absence_rule"]); this.addPermissions(["alsijil.view_register_absence_rule"]);
this.clearForm(); this.clearForm();
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
<absence-reason-group-select <absence-reason-group-select
:rules="$rules().required.build()" :rules="$rules().required.build()"
:value="absenceReason" :value="absenceReason"
:custom-absence-reasons="absenceReasons"
@input="$emit('absence-reason', $event)" @input="$emit('absence-reason', $event)"
/> />
</div> </div>
...@@ -115,6 +116,10 @@ export default { ...@@ -115,6 +116,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
absenceReasons: {
type: Array,
required: true,
},
}, },
computed: { computed: {
maxStartTime() { maxStartTime() {
......
query absenceReasons($orderBy: [String], $filters: JSONString) {
items: coursebookAbsenceReasons(orderBy: $orderBy, filters: $filters) {
id
shortName
name
colour
default
canEdit
canDelete
}
}
...@@ -111,7 +111,6 @@ query documentationsForCoursebook( ...@@ -111,7 +111,6 @@ query documentationsForCoursebook(
oldId oldId
canEdit canEdit
futureNotice futureNotice
canDelete
futureNoticeParticipationStatus futureNoticeParticipationStatus
canEditParticipationStatus canEditParticipationStatus
canViewParticipationStatus canViewParticipationStatus
......
...@@ -72,18 +72,6 @@ class GroupRoleAssignmentQuerySet(QuerySet): ...@@ -72,18 +72,6 @@ class GroupRoleAssignmentQuerySet(QuerySet):
class DocumentationManager(RecurrencePolymorphicManager): class DocumentationManager(RecurrencePolymorphicManager):
"""Manager adding specific methods to documentations.""" """Manager adding specific methods to documentations."""
def get_queryset(self):
"""Ensure often used related data are loaded as well."""
return (
super()
.get_queryset()
.select_related(
"course",
"subject",
)
.prefetch_related("teachers")
)
class ParticipationStatusManager(RecurrencePolymorphicManager): class ParticipationStatusManager(RecurrencePolymorphicManager):
"""Manager adding specific methods to participation statuses.""" """Manager adding specific methods to participation statuses."""
......
...@@ -139,7 +139,6 @@ class Documentation(CalendarEvent): ...@@ -139,7 +139,6 @@ class Documentation(CalendarEvent):
events: list, events: list,
incomplete: Optional[bool] = False, incomplete: Optional[bool] = False,
absences_exist: Optional[bool] = False, absences_exist: Optional[bool] = False,
request: Optional[HttpRequest] = None,
) -> tuple: ) -> tuple:
"""Get all the documentations for the events. """Get all the documentations for the events.
Create dummy documentations if none exist. Create dummy documentations if none exist.
...@@ -149,11 +148,22 @@ class Documentation(CalendarEvent): ...@@ -149,11 +148,22 @@ class Documentation(CalendarEvent):
dummies = [] dummies = []
# Prefetch existing documentations to speed things up # Prefetch existing documentations to speed things up
existing_documentations = Documentation.objects.filter( existing_documentations = (
datetime_start__lte=datetime_end, Documentation.objects.filter(
datetime_end__gte=datetime_start, datetime_start__lte=datetime_end,
amends__in=[e["REFERENCE_OBJECT"] for e in events], datetime_end__gte=datetime_start,
).prefetch_related("participations") amends__in=[e["REFERENCE_OBJECT"] for e in events],
)
.prefetch_related(
"participations",
"participations__person",
"participations__absence_reason",
"teachers",
"personal_notes",
"personal_notes__extra_mark",
)
.select_related("course", "subject")
)
for event in events: for event in events:
if incomplete and event["STATUS"] == "CANCELLED": if incomplete and event["STATUS"] == "CANCELLED":
...@@ -179,6 +189,7 @@ class Documentation(CalendarEvent): ...@@ -179,6 +189,7 @@ class Documentation(CalendarEvent):
) )
): ):
continue continue
doc._amends_prefetched = event_reference_obj
docs.append(doc) docs.append(doc)
elif not absences_exist: elif not absences_exist:
if event_reference_obj.amends: if event_reference_obj.amends:
...@@ -214,7 +225,6 @@ class Documentation(CalendarEvent): ...@@ -214,7 +225,6 @@ class Documentation(CalendarEvent):
start: datetime, start: datetime,
end: datetime, end: datetime,
incomplete: Optional[bool] = False, incomplete: Optional[bool] = False,
request: Optional[HttpRequest] = None,
) -> tuple: ) -> tuple:
"""Get all the documentations for the person from start to end datetime. """Get all the documentations for the person from start to end datetime.
Create dummy documentations if none exist. Create dummy documentations if none exist.
...@@ -233,7 +243,7 @@ class Documentation(CalendarEvent): ...@@ -233,7 +243,7 @@ class Documentation(CalendarEvent):
with_reference_object=True, with_reference_object=True,
) )
return Documentation.get_documentations_for_events(start, end, events, incomplete, request) return Documentation.get_documentations_for_events(start, end, events, incomplete)
@classmethod @classmethod
def parse_dummy( def parse_dummy(
......
...@@ -3,6 +3,7 @@ from datetime import datetime ...@@ -3,6 +3,7 @@ from datetime import datetime
from django.db.models import BooleanField, ExpressionWrapper, Q from django.db.models import BooleanField, ExpressionWrapper, Q
import graphene import graphene
import graphene_django_optimizer
from aleksis.apps.chronos.models import LessonEvent from aleksis.apps.chronos.models import LessonEvent
from aleksis.apps.cursus.models import Course from aleksis.apps.cursus.models import Course
...@@ -13,10 +14,15 @@ from aleksis.core.models import Group, Person ...@@ -13,10 +14,15 @@ from aleksis.core.models import Group, Person
from aleksis.core.schema.base import FilterOrderList from aleksis.core.schema.base import FilterOrderList
from aleksis.core.schema.group import GroupType from aleksis.core.schema.group import GroupType
from aleksis.core.schema.person import PersonType from aleksis.core.schema.person import PersonType
from aleksis.core.util.core_helpers import get_active_school_term, get_site_preferences, has_person from aleksis.core.util.core_helpers import (
filter_active_school_term,
get_active_school_term,
get_site_preferences,
has_person,
)
from ..model_extensions import annotate_person_statistics_for_school_term from ..model_extensions import annotate_person_statistics_for_school_term
from ..models import Documentation, NewPersonalNote, ParticipationStatus from ..models import Documentation, ExtraMark, NewPersonalNote, ParticipationStatus
from .absences import ( from .absences import (
AbsencesForPersonsCreateMutation, AbsencesForPersonsCreateMutation,
) )
...@@ -47,7 +53,6 @@ from .statistics import StatisticsByPersonType ...@@ -47,7 +53,6 @@ from .statistics import StatisticsByPersonType
class Query(graphene.ObjectType): class Query(graphene.ObjectType):
documentations = FilterOrderList(DocumentationType)
documentations_by_course_id = FilterOrderList( documentations_by_course_id = FilterOrderList(
DocumentationType, course_id=graphene.ID(required=True) DocumentationType, course_id=graphene.ID(required=True)
) )
...@@ -104,7 +109,7 @@ class Query(graphene.ObjectType): ...@@ -104,7 +109,7 @@ class Query(graphene.ObjectType):
) )
) )
) )
return documentations return graphene_django_optimizer.query(documentations, info)
def resolve_documentations_for_coursebook( def resolve_documentations_for_coursebook(
root, root,
...@@ -152,6 +157,10 @@ class Query(graphene.ObjectType): ...@@ -152,6 +157,10 @@ class Query(graphene.ObjectType):
} }
) )
school_term = get_active_school_term(info.context)
date_start = date_start if date_start > school_term.date_start else school_term.date_start
date_end = date_end if date_end < school_term.date_end else school_term.date_end
events = LessonEvent.get_single_events( events = LessonEvent.get_single_events(
datetime.combine(date_start, datetime.min.time()), datetime.combine(date_start, datetime.min.time()),
datetime.combine(date_end, datetime.max.time()), datetime.combine(date_end, datetime.max.time()),
...@@ -167,7 +176,6 @@ class Query(graphene.ObjectType): ...@@ -167,7 +176,6 @@ class Query(graphene.ObjectType):
events, events,
incomplete, incomplete,
absences_exist, absences_exist,
info.context,
) )
return docs + dummies return docs + dummies
...@@ -182,8 +190,10 @@ class Query(graphene.ObjectType): ...@@ -182,8 +190,10 @@ class Query(graphene.ObjectType):
else: else:
return [] return []
school_term = get_active_school_term(info.context)
return ( return (
Group.objects.for_current_school_term_or_all() Group.objects.for_school_term(school_term)
.filter( .filter(
pk__in=Group.objects.filter(members=person) pk__in=Group.objects.filter(members=person)
.values_list("id", flat=True) .values_list("id", flat=True)
...@@ -211,6 +221,9 @@ class Query(graphene.ObjectType): ...@@ -211,6 +221,9 @@ class Query(graphene.ObjectType):
person = info.context.user.person person = info.context.user.person
else: else:
return [] return []
school_term = get_active_school_term(info.context)
return Course.objects.filter( return Course.objects.filter(
pk__in=( pk__in=(
Course.objects.filter(teachers=person) Course.objects.filter(teachers=person)
...@@ -223,20 +236,22 @@ class Query(graphene.ObjectType): ...@@ -223,20 +236,22 @@ class Query(graphene.ObjectType):
) )
) )
) )
).filter(groups__in=Group.objects.for_current_school_term_or_all()) ).filter(groups__in=Group.objects.for_school_term(school_term))
@staticmethod @staticmethod
def resolve_absence_creation_persons(root, info, **kwargs): def resolve_absence_creation_persons(root, info, **kwargs):
if not info.context.user.has_perm("alsijil.register_absence"): if not info.context.user.has_perm("alsijil.register_absence"):
group_types = get_site_preferences()["alsijil__group_types_register_absence"] group_types = get_site_preferences()["alsijil__group_types_register_absence"]
school_term = get_active_school_term(info.context)
if group_types: if group_types:
return Person.objects.filter( return Person.objects.filter(
member_of__in=Group.objects.filter( member_of__in=Group.objects.for_school_term(school_term).filter(
owners=info.context.user.person, group_type__in=group_types owners=info.context.user.person, group_type__in=group_types
) )
) )
else: else:
return Person.objects.filter(member_of__owners=info.context.user.person) qs = Person.objects.filter(member_of__owners=info.context.user.person)
return filter_active_school_term(info.context, qs, "member_of__school_term")
return Person.objects.all() return Person.objects.all()
@staticmethod @staticmethod
...@@ -255,13 +270,18 @@ class Query(graphene.ObjectType): ...@@ -255,13 +270,18 @@ class Query(graphene.ObjectType):
person, person,
start, start,
end, end,
info.context,
) )
lessons_for_person.append(LessonsForPersonType(id=person, lessons=docs + dummies)) lessons_for_person.append(LessonsForPersonType(id=person, lessons=docs + dummies))
return lessons_for_person return lessons_for_person
@staticmethod
def resolve_extra_marks(root, info, **kwargs):
if info.context.user.has_perm("alsijil.fetch_extramarks_rule"):
return ExtraMark.objects.all()
raise []
@staticmethod @staticmethod
def resolve_coursebook_absence_reasons(root, info, **kwargs): def resolve_coursebook_absence_reasons(root, info, **kwargs):
if not info.context.user.has_perm("kolego.fetch_absencereasons_rule"): if not info.context.user.has_perm("kolego.fetch_absencereasons_rule"):
...@@ -274,9 +294,12 @@ class Query(graphene.ObjectType): ...@@ -274,9 +294,12 @@ class Query(graphene.ObjectType):
if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person): if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
return None return None
school_term = get_active_school_term(info.context) school_term = get_active_school_term(info.context)
return annotate_person_statistics_for_school_term( return graphene_django_optimizer.query(
Person.objects.filter(id=person.id), school_term annotate_person_statistics_for_school_term(
).first() Person.objects.filter(id=person.id), school_term
).first(),
info,
)
@staticmethod @staticmethod
def resolve_participations_of_person(root, info, person): def resolve_participations_of_person(root, info, person):
...@@ -284,12 +307,15 @@ class Query(graphene.ObjectType): ...@@ -284,12 +307,15 @@ class Query(graphene.ObjectType):
if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person): if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
return [] return []
school_term = get_active_school_term(info.context) school_term = get_active_school_term(info.context)
return ParticipationStatus.objects.filter( return graphene_django_optimizer.query(
person=person, ParticipationStatus.objects.filter(
absence_reason__isnull=False, person=person,
datetime_start__date__gte=school_term.date_start, absence_reason__isnull=False,
datetime_end__date__lte=school_term.date_end, datetime_start__date__gte=school_term.date_start,
).order_by("-related_documentation__datetime_start") datetime_end__date__lte=school_term.date_end,
).order_by("-related_documentation__datetime_start"),
info,
)
@staticmethod @staticmethod
def resolve_personal_notes_for_person(root, info, person): def resolve_personal_notes_for_person(root, info, person):
...@@ -297,13 +323,16 @@ class Query(graphene.ObjectType): ...@@ -297,13 +323,16 @@ class Query(graphene.ObjectType):
if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person): if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
return [] return []
school_term = get_active_school_term(info.context) school_term = get_active_school_term(info.context)
return NewPersonalNote.objects.filter( return graphene_django_optimizer.query(
person=person, NewPersonalNote.objects.filter(
documentation__in=Documentation.objects.filter( person=person,
datetime_start__date__gte=school_term.date_start, documentation__in=Documentation.objects.filter(
datetime_end__date__lte=school_term.date_end, datetime_start__date__gte=school_term.date_start,
), datetime_end__date__lte=school_term.date_end,
).order_by("-documentation__datetime_start") ),
).order_by("-documentation__datetime_start"),
info,
)
@staticmethod @staticmethod
def resolve_statistics_by_group(root, info, group): def resolve_statistics_by_group(root, info, group):
...@@ -313,7 +342,9 @@ class Query(graphene.ObjectType): ...@@ -313,7 +342,9 @@ class Query(graphene.ObjectType):
school_term = get_active_school_term(info.context) school_term = get_active_school_term(info.context)
members = group.members.all() members = group.members.all()
return annotate_person_statistics_for_school_term(members, school_term, group=group) return graphene_django_optimizer.query(
annotate_person_statistics_for_school_term(members, school_term, group=group), info
)
class Mutation(graphene.ObjectType): class Mutation(graphene.ObjectType):
......
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
import graphene import graphene
from graphene_django import bypass_get_queryset
from graphene_django.types import DjangoObjectType from graphene_django.types import DjangoObjectType
from reversion import create_revision, set_comment, set_user from reversion import create_revision, set_comment, set_user
...@@ -32,7 +33,6 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp ...@@ -32,7 +33,6 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
fields = ( fields = (
"id", "id",
"course", "course",
"amends",
"subject", "subject",
"topic", "topic",
"homework", "homework",
...@@ -62,6 +62,14 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp ...@@ -62,6 +62,14 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
old_id = graphene.ID(required=False) old_id = graphene.ID(required=False)
@staticmethod @staticmethod
@bypass_get_queryset
def resolve_amends(root: Documentation, info, **kwargs):
if hasattr(root, "_amends_prefetched"):
return root._amends_prefetched
return root.amends
@staticmethod
@bypass_get_queryset
def resolve_teachers(root: Documentation, info, **kwargs): def resolve_teachers(root: Documentation, info, **kwargs):
if not str(root.pk).startswith("DUMMY") and hasattr(root, "teachers"): if not str(root.pk).startswith("DUMMY") and hasattr(root, "teachers"):
return root.teachers return root.teachers
...@@ -100,6 +108,7 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp ...@@ -100,6 +108,7 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
) )
@staticmethod @staticmethod
@bypass_get_queryset
def resolve_participations(root: Documentation, info, **kwargs): def resolve_participations(root: Documentation, info, **kwargs):
# A dummy documentation will not have any participations # A dummy documentation will not have any participations
if str(root.pk).startswith("DUMMY") or not hasattr(root, "participations"): if str(root.pk).startswith("DUMMY") or not hasattr(root, "participations"):
...@@ -112,6 +121,11 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp ...@@ -112,6 +121,11 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
p for p in root.participations.all() if p.person == info.context.user.person p for p in root.participations.all() if p.person == info.context.user.person
] ]
return [] return []
# Annotate participations with prefetched documentation data for personal notes
for participation in root.participations.all():
participation._prefetched_documentation = root
return root.participations.all() return root.participations.all()
......
...@@ -23,12 +23,6 @@ class ExtraMarkType( ...@@ -23,12 +23,6 @@ class ExtraMarkType(
model = ExtraMark model = ExtraMark
fields = ("id", "short_name", "name", "colour_fg", "colour_bg", "show_in_coursebook") fields = ("id", "short_name", "name", "colour_fg", "colour_bg", "show_in_coursebook")
@classmethod
def get_queryset(cls, queryset, info):
if info.context.user.has_perm("alsijil.fetch_extramarks_rule"):
return queryset
raise PermissionDenied()
class ExtraMarkBatchCreateMutation(BaseBatchCreateMutation): class ExtraMarkBatchCreateMutation(BaseBatchCreateMutation):
class Meta: class Meta:
......
...@@ -41,6 +41,12 @@ class ParticipationStatusType( ...@@ -41,6 +41,12 @@ class ParticipationStatusType(
@staticmethod @staticmethod
def resolve_notes_with_extra_mark(root: ParticipationStatus, info, **kwargs): def resolve_notes_with_extra_mark(root: ParticipationStatus, info, **kwargs):
if hasattr(root, "_prefetched_documentation"):
return [
p
for p in root._prefetched_documentation.personal_notes.all()
if p.person_id == root.person_id and p.extra_mark
]
return NewPersonalNote.objects.filter( return NewPersonalNote.objects.filter(
person=root.person, person=root.person,
documentation=root.related_documentation, documentation=root.related_documentation,
...@@ -49,6 +55,12 @@ class ParticipationStatusType( ...@@ -49,6 +55,12 @@ class ParticipationStatusType(
@staticmethod @staticmethod
def resolve_notes_with_note(root: ParticipationStatus, info, **kwargs): def resolve_notes_with_note(root: ParticipationStatus, info, **kwargs):
if hasattr(root, "_prefetched_documentation"):
return [
p
for p in root._prefetched_documentation.personal_notes.all()
if p.person_id == root.person_id and p.note
]
return NewPersonalNote.objects.filter( return NewPersonalNote.objects.filter(
person=root.person, person=root.person,
documentation=root.related_documentation, documentation=root.related_documentation,
......
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