Skip to content
Snippets Groups Projects
documentation.py 5.91 KiB
Newer Older
Jonathan Weth's avatar
Jonathan Weth committed
from datetime import datetime
Hangzhi Yu's avatar
Hangzhi Yu committed

from django.core.exceptions import PermissionDenied
from django.utils.timezone import localdate, localtime
Hangzhi Yu's avatar
Hangzhi Yu committed

import graphene
from graphene_django.types import DjangoObjectType
from guardian.shortcuts import get_objects_for_user

from aleksis.apps.alsijil.util.predicates import can_edit_documentation, is_in_allowed_time_range
from aleksis.apps.chronos.models import LessonEvent
from aleksis.apps.cursus.models import Subject
from aleksis.apps.cursus.schema import CourseType, SubjectType
from aleksis.core.models import Person
from aleksis.core.schema.base import (
    DjangoFilterMixin,
    PermissionsTypeMixin,
)
from aleksis.core.util.core_helpers import get_site_preferences
Hangzhi Yu's avatar
Hangzhi Yu committed

from ..models import Documentation


class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType):
    class Meta:
        model = Documentation
Jonathan Weth's avatar
Jonathan Weth committed
        fields = (
            "id",
            "course",
            "lesson_event",
            "subject",
            "topic",
            "homework",
            "group_note",
            "datetime_start",
            "datetime_end",
            "date_start",
            "date_end",
Julian's avatar
Julian committed
            "teachers",
Jonathan Weth's avatar
Jonathan Weth committed
        )
        filter_fields = {
            "id": ["exact", "lte", "gte"],
            "course__name": ["exact"],
        }

    course = graphene.Field(CourseType, required=False)
    subject = graphene.Field(SubjectType, required=False)

    old_id = graphene.ID(required=False)

Julian's avatar
Julian committed
    @staticmethod
    def resolve_teachers(root: Documentation, info, **kwargs):
        if not str(root.pk).startswith("DUMMY") and hasattr(root, "teachers"):
Hangzhi Yu's avatar
Hangzhi Yu committed
            return root.teachers
        return root.lesson_event.teachers
    @staticmethod
    def resolve_future_notice(root: Documentation, info, **kwargs):
        """Show whether the user can't edit the documentation because it's in the future."""
        return not is_in_allowed_time_range(info.context.user, root) and can_edit_documentation(
            info.context.user, root
        )

    @classmethod
    def get_queryset(cls, queryset, info):
        return get_objects_for_user(info.context.user, "alsijil.view_documentation", queryset)

class DocumentationInputType(graphene.InputObjectType):
    id = graphene.ID(required=True)
    course = graphene.ID(required=False)
    subject = graphene.ID(required=False)
Julian's avatar
Julian committed
    teachers = graphene.List(graphene.ID, required=False)

    topic = graphene.String(required=False)
    homework = graphene.String(required=False)
    group_note = graphene.String(required=False)


class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
    class Arguments:
        input = graphene.List(DocumentationInputType)
    documentations = graphene.List(DocumentationType)
    def create_or_update(cls, info, doc):
Hangzhi Yu's avatar
Hangzhi Yu committed
        _id = doc.id
Hangzhi Yu's avatar
Hangzhi Yu committed
        # Sadly, we can't use the update_or_create method since create_defaults
        # is only introduced in Django 5.0
        if _id.startswith("DUMMY"):
            dummy, lesson_event_id, datetime_start_iso, datetime_end_iso = _id.split(";")
            lesson_event = LessonEvent.objects.get(id=lesson_event_id)
            datetime_start = datetime.fromisoformat(datetime_start_iso).astimezone(
                lesson_event.timezone
            )
            datetime_end = datetime.fromisoformat(datetime_end_iso).astimezone(
                lesson_event.timezone
            )

            if info.context.user.has_perm(
Julian's avatar
Julian committed
                "alsijil.add_documentation_for_lesson_event_rule", lesson_event
            ) and (
                get_site_preferences()["alsijil__allow_edit_future_documentations"] == "all"
                or (
                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
                    == "current_day"
                    and datetime_start.date() <= localdate()
                )
                or (
                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
                    == "current_time"
                    and datetime_start <= localtime()
                )
                # Timezone removal is necessary due to ISO style offsets are no valid timezones.
                # Instead, we take the timezone from the lesson_event and save it in a dedicated field.
                obj = Documentation.objects.create(
                    datetime_start=datetime_start,
                    datetime_end=datetime_end,
                    lesson_event=lesson_event,
                    course=lesson_event.course,
                    subject=lesson_event.subject,
                    topic=doc.topic or "",
                    homework=doc.homework or "",
                    group_note=doc.group_note or "",
                )
                if doc.teachers is not None:
                    obj.teachers.add(*doc.teachers)
                else:
                    obj.teachers.set(lesson_event.teachers.all())
                obj.save()
                return obj
            raise PermissionDenied()
        else:
Hangzhi Yu's avatar
Hangzhi Yu committed
            obj = Documentation.objects.get(id=_id)

            if not info.context.user.has_perm("alsijil.edit_documentation_rule", obj):
                raise PermissionDenied()

            if doc.topic is not None:
                obj.topic = doc.topic
            if doc.homework is not None:
                obj.homework = doc.homework
            if doc.group_note is not None:
                obj.group_note = doc.group_note

            if doc.subject is not None:
                obj.subject = Subject.objects.get(pk=doc.subject)
            if doc.teachers is not None:
                obj.teachers.set(Person.objects.filter(pk__in=doc.teachers))

            obj.save()
            return obj

    @classmethod
Hangzhi Yu's avatar
Hangzhi Yu committed
    def mutate(cls, root, info, input):  # noqa
        objs = [cls.create_or_update(info, doc) for doc in input]

        return DocumentationBatchCreateOrUpdateMutation(documentations=objs)