Exemple #1
0
 def serialize(obj):
     return {
         "id": obj.id,
         "visit_time": (
             format_datetime_local(as_local_time(obj.visit.visit_time))),
         "grade_time": format_datetime_local(as_local_time(obj.grade_time)),
         "value": obj.value(),
     }
Exemple #2
0
def view_reopen_session(pctx, flow_session_id, opportunity_id):
    if pctx.role not in [
            participation_role.instructor,
            participation_role.teaching_assistant
    ]:
        raise PermissionDenied()

    request = pctx.request

    session = get_object_or_404(FlowSession, id=int(flow_session_id))

    from course.content import get_flow_desc
    try:
        flow_desc = get_flow_desc(pctx.repo, pctx.course, session.flow_id,
                                  pctx.course_commit_sha)
    except ObjectDoesNotExist:
        raise http.Http404()

    if request.method == "POST":
        form = ReopenSessionForm(flow_desc, session.access_rules_tag,
                                 request.POST, request.FILES)

        if form.is_valid():
            new_access_rules_tag = form.cleaned_data["set_access_rules_tag"]
            if new_access_rules_tag == NONE_SESSION_TAG:
                new_access_rules_tag = None

            session.access_rules_tag = new_access_rules_tag

            from relate.utils import (local_now, as_local_time,
                                      format_datetime_local)
            session.append_comment(
                ugettext("Session reopened at %(now)s by %(user)s, "
                         "previous completion time was '%(completion_time)s': "
                         "%(comment)s.") % {
                             "now":
                             format_datetime_local(local_now()),
                             "user":
                             pctx.request.user,
                             "completion_time":
                             format_datetime_local(
                                 as_local_time(session.completion_time)),
                             "comment":
                             form.cleaned_data["comment"]
                         })
            session.save()

            from course.flow import reopen_session
            reopen_session(session, suppress_log=True)

            return redirect("relate-view_single_grade", pctx.course.identifier,
                            session.participation.id, opportunity_id)

    else:
        form = ReopenSessionForm(flow_desc, session.access_rules_tag)

    return render(request, "generic-form.html", {
        "form": form,
        "form_description": _("Reopen session")
    })
Exemple #3
0
def view_reopen_session(pctx, flow_session_id, opportunity_id):
    if pctx.role not in [
            participation_role.instructor,
            participation_role.teaching_assistant]:
        raise PermissionDenied()

    request = pctx.request

    session = get_object_or_404(FlowSession, id=int(flow_session_id))

    from course.content import get_flow_desc
    try:
        flow_desc = get_flow_desc(pctx.repo, pctx.course, session.flow_id,
                pctx.course_commit_sha)
    except ObjectDoesNotExist:
        raise http.Http404()

    if request.method == "POST":
        form = ReopenSessionForm(flow_desc, session.access_rules_tag,
            request.POST, request.FILES)

        if form.is_valid():
            new_access_rules_tag = form.cleaned_data["set_access_rules_tag"]
            if new_access_rules_tag == NONE_SESSION_TAG:
                new_access_rules_tag = None

            session.access_rules_tag = new_access_rules_tag

            from relate.utils import (
                    local_now, as_local_time,
                    format_datetime_local)
            session.append_comment(
                    ugettext("Session reopened at %(now)s by %(user)s, "
                        "previous completion time was '%(completion_time)s': "
                        "%(comment)s.") % {
                            "now": format_datetime_local(local_now()),
                            "user": pctx.request.user,
                            "completion_time": format_datetime_local(
                                as_local_time(session.completion_time)),
                            "comment": form.cleaned_data["comment"]
                            })
            session.save()

            from course.flow import reopen_session
            reopen_session(session, suppress_log=True)

            return redirect("relate-view_single_grade",
                    pctx.course.identifier,
                    session.participation.id,
                    opportunity_id)

    else:
        form = ReopenSessionForm(flow_desc, session.access_rules_tag)

    return render(request, "generic-form.html", {
        "form": form,
        "form_description": _("Reopen session")
        })
Exemple #4
0
def strify_session_for_exception(session):
    from relate.utils import as_local_time
    result = ("started at %s" % as_local_time(session.start_time)
            .strftime('%b %d %Y - %I:%M %p'))

    if session.access_rules_tag:
        result += " tagged '%s'" % session.access_rules_tag

    return result
Exemple #5
0
def strify_session_for_exception(session):
    from relate.utils import as_local_time, format_datetime_local
    # Translators: %s is the string of the start time of a session.
    result = (_("started at %s") %
              format_datetime_local(as_local_time(session.start_time)))

    if session.access_rules_tag:
        result += " tagged '%s'" % session.access_rules_tag

    return result
Exemple #6
0
def strify_session_for_exception(session):
    from relate.utils import as_local_time, format_datetime_local
    # Translators: %s is the string of the start time of a session.
    result = (_("started at %s") % format_datetime_local(
        as_local_time(session.start_time)))

    if session.access_rules_tag:
        result += " tagged '%s'" % session.access_rules_tag

    return result
Exemple #7
0
def reopen_session(session, force=False, suppress_log=False):
    if session.in_progress:
        raise RuntimeError(_("Can't reopen a session that's already in progress"))
    if session.participation is None:
        raise RuntimeError(_("Can't reopen anonymous sessions"))

    session.in_progress = True
    session.points = None
    session.max_points = None

    if not suppress_log:
        session.append_comment(
            _("Session reopened at %(now)s, previous completion time " "was '%(complete_time)s'.")
            % {
                "now": format_datetime_local(local_now()),
                "complete_time": format_datetime_local(as_local_time(session.completion_time)),
            }
        )

    session.completion_time = None
    session.save()
Exemple #8
0
    def test_all_day_event(self):
        self.switch_to_fake_commit_sha()

        # lecture 2, no end_time
        lecture2_start_time = datetime.datetime(2019, 1, 1, tzinfo=pytz.UTC)

        self.mock_get_now_or_fake_time.return_value = (
                lecture2_start_time + timedelta(minutes=5))

        lecture2_evt = factories.EventFactory(
            kind=self.default_event_kind, course=self.course,
            all_day=True,
            time=lecture2_start_time, ordinal=2)

        # lecture 3
        lecture3_start_time = lecture2_start_time + timedelta(weeks=1)
        factories.EventFactory(
            kind=self.default_event_kind, course=self.course,
            time=lecture3_start_time, ordinal=3)

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': lecture2_evt.pk, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-%i' % lecture2_evt.pk})

        # now we add end_time of lecture 2 evt to a time which is not midnight
        lecture2_end_time = lecture2_start_time + timedelta(hours=18)
        lecture2_evt.end_time = lecture2_end_time
        lecture2_evt.save()

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': lecture2_evt.pk, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-%i' % lecture2_evt.pk,
             'end': lecture2_end_time.isoformat()
             })

        # now we update end_time of lecture 2 evt to midnight
        while True:
            local_t = as_local_time(lecture2_end_time)
            end_midnight = datetime.time(tzinfo=local_t.tzinfo)
            if local_t.time() == end_midnight:
                lecture2_evt.end_time = lecture2_end_time
                lecture2_evt.save()
                break

            lecture2_end_time += timedelta(hours=1)

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': lecture2_evt.pk, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-%i' % lecture2_evt.pk,
             'end': lecture2_end_time.isoformat()
             })
Exemple #9
0
def grant_exception_stage_3(pctx, participation_id, flow_id, session_id):
    # type: (CoursePageContext, int, Text, int) -> http.HttpResponse

    if not pctx.has_permission(pperm.grant_exception):
        raise PermissionDenied(_("may not grant exceptions"))

    participation = get_object_or_404(Participation, id=participation_id)

    from course.content import get_flow_desc
    try:
        flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_id,
                                  pctx.course_commit_sha)
    except ObjectDoesNotExist:
        raise http.Http404()

    session = FlowSession.objects.get(id=int(session_id))

    now_datetime = get_now_or_fake_time(pctx.request)
    from course.utils import (get_session_access_rule,
                              get_session_grading_rule)
    access_rule = get_session_access_rule(session, flow_desc, now_datetime)
    grading_rule = get_session_grading_rule(session, flow_desc, now_datetime)

    request = pctx.request
    if request.method == "POST":
        form = ExceptionStage3Form({}, flow_desc, session.access_rules_tag,
                                   request.POST)

        from course.constants import flow_rule_kind

        if form.is_valid():
            permissions = [
                key for key, _ in FLOW_PERMISSION_CHOICES
                if form.cleaned_data[key]
            ]

            from course.validation import (validate_session_access_rule,
                                           validate_session_grading_rule,
                                           ValidationContext)
            from relate.utils import dict_to_struct
            vctx = ValidationContext(repo=pctx.repo,
                                     commit_sha=pctx.course_commit_sha)

            flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_id,
                                      pctx.course_commit_sha)

            tags = []  # type: List[Text]
            if hasattr(flow_desc, "rules"):
                try:
                    from typing import Text  # noqa
                except ImportError:
                    Text = None  # noqa
                tags = cast(List[Text], getattr(flow_desc.rules, "tags",
                                                []))  # type: ignore  # noqa

            # {{{ put together access rule

            if form.cleaned_data["create_access_exception"]:
                new_access_rule = {"permissions": permissions}

                if (form.cleaned_data.get("restrict_to_same_tag")
                        and session.access_rules_tag is not None):
                    new_access_rule["if_has_tag"] = session.access_rules_tag

                validate_session_access_rule(
                    vctx, ugettext("newly created exception"),
                    dict_to_struct(new_access_rule), tags)

                fre_access = FlowRuleException(
                    flow_id=flow_id,
                    participation=participation,
                    expiration=form.cleaned_data["access_expires"],
                    creator=pctx.request.user,
                    comment=form.cleaned_data["comment"],
                    kind=flow_rule_kind.access,
                    rule=new_access_rule)
                fre_access.save()

            # }}}

            new_access_rules_tag = form.cleaned_data.get(
                "set_access_rules_tag")
            if new_access_rules_tag == NONE_SESSION_TAG:
                new_access_rules_tag = None

            if session.access_rules_tag != new_access_rules_tag:
                session.access_rules_tag = new_access_rules_tag
                session.save()

            # {{{ put together grading rule

            if form.cleaned_data["create_grading_exception"]:
                due = form.cleaned_data["due"]
                if form.cleaned_data["due_same_as_access_expiration"]:
                    due = form.cleaned_data["access_expires"]

                descr = ugettext("Granted excecption")
                if form.cleaned_data["credit_percent"] is not None:
                    descr += string_concat(" (%.1f%% ", ugettext('credit'), ")") \
                            % form.cleaned_data["credit_percent"]

                due_local_naive = due
                if due_local_naive is not None:
                    from relate.utils import as_local_time
                    due_local_naive = (as_local_time(due_local_naive).replace(
                        tzinfo=None))

                new_grading_rule = {
                    "description": descr,
                }

                if due_local_naive is not None:
                    new_grading_rule["due"] = due_local_naive
                    new_grading_rule["if_completed_before"] = due_local_naive

                for attr_name in [
                        "credit_percent", "bonus_points", "max_points",
                        "max_points_enforced_cap", "generates_grade"
                ]:
                    if form.cleaned_data[attr_name] is not None:
                        new_grading_rule[attr_name] = form.cleaned_data[
                            attr_name]

                if (form.cleaned_data.get("restrict_to_same_tag")
                        and session.access_rules_tag is not None):
                    new_grading_rule["if_has_tag"] = session.access_rules_tag

                validate_session_grading_rule(
                    vctx, ugettext("newly created exception"),
                    dict_to_struct(new_grading_rule), tags,
                    grading_rule.grade_identifier)

                fre_grading = FlowRuleException(
                    flow_id=flow_id,
                    participation=participation,
                    creator=pctx.request.user,
                    comment=form.cleaned_data["comment"],
                    kind=flow_rule_kind.grading,
                    rule=new_grading_rule)
                fre_grading.save()

            # }}}

            messages.add_message(
                pctx.request, messages.SUCCESS,
                ugettext("Exception granted to '%(participation)s' "
                         "for '%(flow_id)s'.") % {
                             'participation': participation,
                             'flow_id': flow_id
                         })
            return redirect("relate-grant_exception", pctx.course.identifier)

    else:
        data = {
            "restrict_to_same_tag": session.access_rules_tag is not None,
            #"due_same_as_access_expiration": True,
            "due": grading_rule.due,
            "generates_grade": grading_rule.generates_grade,
            "credit_percent": grading_rule.credit_percent,
            "bonus_points": grading_rule.bonus_points,
            "max_points": grading_rule.max_points,
            "max_points_enforced_cap": grading_rule.max_points_enforced_cap,
        }
        for perm in access_rule.permissions:
            data[perm] = True

        form = ExceptionStage3Form(data, flow_desc, session.access_rules_tag)

    return render_course_page(
        pctx, "course/generic-course-form.html", {
            "form": form,
            "form_description": ugettext("Grant Exception"),
            "form_text": string_concat(
                "<div class='well'>",
                ugettext("Granting exception to '%(participation)s' "
                         "for '%(flow_id)s' (session %(session)s)."), "</div>")
            % {
                'participation': participation,
                'flow_id': flow_id,
                'session': strify_session_for_exception(session)
            },
        })
Exemple #10
0
def view_calendar(pctx):
    from course.content import markup_to_html, parse_date_spec

    from course.views import get_now_or_fake_time
    now = get_now_or_fake_time(pctx.request)

    if not pctx.has_permission(pperm.view_calendar):
        raise PermissionDenied(_("may not view calendar"))

    events_json = []

    from course.content import get_raw_yaml_from_repo
    try:
        event_descr = get_raw_yaml_from_repo(pctx.repo,
                pctx.course.events_file, pctx.course_commit_sha)
    except ObjectDoesNotExist:
        event_descr = {}

    event_kinds_desc = event_descr.get("event_kinds", {})
    event_info_desc = event_descr.get("events", {})

    event_info_list = []

    events = sorted(
            Event.objects
            .filter(
                course=pctx.course,
                shown_in_calendar=True),
            key=lambda evt: (
                -evt.time.year, -evt.time.month, -evt.time.day,
                evt.time.hour, evt.time.minute, evt.time.second))

    for event in events:
        kind_desc = event_kinds_desc.get(event.kind)

        human_title = six.text_type(event)

        event_json = {
                "id": event.id,
                "start": event.time.isoformat(),
                "allDay": event.all_day,
                }
        if event.end_time is not None:
            event_json["end"] = event.end_time.isoformat()

        if kind_desc is not None:
            if "color" in kind_desc:
                event_json["color"] = kind_desc["color"]
            if "title" in kind_desc:
                if event.ordinal is not None:
                    human_title = kind_desc["title"].format(nr=event.ordinal)
                else:
                    human_title = kind_desc["title"]

        description = None
        show_description = True
        event_desc = event_info_desc.get(six.text_type(event))
        if event_desc is not None:
            if "description" in event_desc:
                description = markup_to_html(
                        pctx.course, pctx.repo, pctx.course_commit_sha,
                        event_desc["description"])

            if "title" in event_desc:
                human_title = event_desc["title"]

            if "color" in event_desc:
                event_json["color"] = event_desc["color"]

            if "show_description_from" in event_desc:
                ds = parse_date_spec(
                        pctx.course, event_desc["show_description_from"])
                if now < ds:
                    show_description = False

            if "show_description_until" in event_desc:
                ds = parse_date_spec(
                        pctx.course, event_desc["show_description_until"])
                if now > ds:
                    show_description = False

        event_json["title"] = human_title

        if show_description and description:
            event_json["url"] = "#event-%d" % event.id

            start_time = event.time
            end_time = event.end_time

            if event.all_day:
                start_time = start_time.date()
                if end_time is not None:
                    local_end_time = as_local_time(end_time)
                    end_midnight = datetime.time(tzinfo=local_end_time.tzinfo)
                    if local_end_time.time() == end_midnight:
                        end_time = (end_time - datetime.timedelta(days=1)).date()
                    else:
                        end_time = end_time.date()

            event_info_list.append(
                    EventInfo(
                        id=event.id,
                        human_title=human_title,
                        start_time=start_time,
                        end_time=end_time,
                        description=description
                        ))

        events_json.append(event_json)

    default_date = now.date()
    if pctx.course.end_date is not None and default_date > pctx.course.end_date:
        default_date = pctx.course.end_date

    from json import dumps
    return render_course_page(pctx, "course/calendar.html", {
        "events_json": dumps(events_json),
        "event_info_list": event_info_list,
        "default_date": default_date.isoformat(),
    })
Exemple #11
0
def view_calendar(pctx):
    from course.content import markup_to_html, parse_date_spec

    from course.views import get_now_or_fake_time

    now = get_now_or_fake_time(pctx.request)

    if not pctx.has_permission(pperm.view_calendar):
        raise PermissionDenied(_("may not view calendar"))

    events_json = []

    from course.content import get_raw_yaml_from_repo

    try:
        event_descr = get_raw_yaml_from_repo(pctx.repo, pctx.course.events_file, pctx.course_commit_sha)
    except ObjectDoesNotExist:
        event_descr = {}

    event_kinds_desc = event_descr.get("event_kinds", {})
    event_info_desc = event_descr.get("events", {})

    event_info_list = []

    for event in Event.objects.filter(course=pctx.course, shown_in_calendar=True).order_by("-time"):
        kind_desc = event_kinds_desc.get(event.kind)

        human_title = six.text_type(event)

        event_json = {"id": event.id, "start": event.time.isoformat(), "allDay": event.all_day}
        if event.end_time is not None:
            event_json["end"] = event.end_time.isoformat()

        if kind_desc is not None:
            if "color" in kind_desc:
                event_json["color"] = kind_desc["color"]
            if "title" in kind_desc:
                if event.ordinal is not None:
                    human_title = kind_desc["title"].format(nr=event.ordinal)
                else:
                    human_title = kind_desc["title"]

        description = None
        show_description = True
        event_desc = event_info_desc.get(six.text_type(event))
        if event_desc is not None:
            if "description" in event_desc:
                description = markup_to_html(pctx.course, pctx.repo, pctx.course_commit_sha, event_desc["description"])

            if "title" in event_desc:
                human_title = event_desc["title"]

            if "color" in event_desc:
                event_json["color"] = event_desc["color"]

            if "show_description_from" in event_desc:
                ds = parse_date_spec(pctx.course, event_desc["show_description_from"])
                if now < ds:
                    show_description = False

            if "show_description_until" in event_desc:
                ds = parse_date_spec(pctx.course, event_desc["show_description_until"])
                if now > ds:
                    show_description = False

        event_json["title"] = human_title

        if show_description and description:
            event_json["url"] = "#event-%d" % event.id

            start_time = event.time
            end_time = event.end_time

            if event.all_day:
                start_time = start_time.date()
                local_end_time = as_local_time(end_time)
                end_midnight = datetime.time(tzinfo=local_end_time.tzinfo)
                if local_end_time.time() == end_midnight:
                    end_time = (end_time - datetime.timedelta(days=1)).date()
                else:
                    end_time = end_time.date()

            event_info_list.append(
                EventInfo(
                    id=event.id,
                    human_title=human_title,
                    start_time=start_time,
                    end_time=end_time,
                    description=description,
                )
            )

        events_json.append(event_json)

    default_date = now.date()
    if pctx.course.end_date is not None and default_date > pctx.course.end_date:
        default_date = pctx.course.end_date

    from json import dumps

    return render_course_page(
        pctx,
        "course/calendar.html",
        {
            "events_json": dumps(events_json),
            "event_info_list": event_info_list,
            "default_date": default_date.isoformat(),
        },
    )
Exemple #12
0
def grant_exception_stage_3(pctx, participation_id, flow_id, session_id):
    # type: (CoursePageContext, int, Text, int) -> http.HttpResponse

    if not pctx.has_permission(pperm.grant_exception):
        raise PermissionDenied(_("may not grant exceptions"))

    participation = get_object_or_404(Participation, id=participation_id)

    from course.content import get_flow_desc
    try:
        flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_id,
                pctx.course_commit_sha)
    except ObjectDoesNotExist:
        raise http.Http404()

    session = FlowSession.objects.get(id=int(session_id))

    now_datetime = get_now_or_fake_time(pctx.request)
    from course.utils import (
            get_session_access_rule,
            get_session_grading_rule)
    access_rule = get_session_access_rule(session, flow_desc, now_datetime)
    grading_rule = get_session_grading_rule(session, flow_desc, now_datetime)

    request = pctx.request
    if request.method == "POST":
        form = ExceptionStage3Form(
                {}, flow_desc, session.access_rules_tag, request.POST)

        from course.constants import flow_rule_kind

        if form.is_valid():
            permissions = [
                    key
                    for key, _ in FLOW_PERMISSION_CHOICES
                    if form.cleaned_data[key]]

            from course.validation import (
                    validate_session_access_rule,
                    validate_session_grading_rule,
                    ValidationContext)
            from relate.utils import dict_to_struct
            vctx = ValidationContext(
                    repo=pctx.repo,
                    commit_sha=pctx.course_commit_sha)

            flow_desc = get_flow_desc(pctx.repo,
                    pctx.course,
                    flow_id, pctx.course_commit_sha)
            tags = None
            if hasattr(flow_desc, "rules"):
                tags = getattr(flow_desc.rules, "tags", None)

            # {{{ put together access rule

            if form.cleaned_data["create_access_exception"]:
                new_access_rule = {"permissions": permissions}

                if (form.cleaned_data.get("restrict_to_same_tag")
                        and session.access_rules_tag is not None):
                    new_access_rule["if_has_tag"] = session.access_rules_tag

                validate_session_access_rule(
                        vctx, ugettext("newly created exception"),
                        dict_to_struct(new_access_rule), tags)

                fre_access = FlowRuleException(
                    flow_id=flow_id,
                    participation=participation,
                    expiration=form.cleaned_data["access_expires"],
                    creator=pctx.request.user,
                    comment=form.cleaned_data["comment"],
                    kind=flow_rule_kind.access,
                    rule=new_access_rule)
                fre_access.save()

            # }}}

            new_access_rules_tag = form.cleaned_data.get("set_access_rules_tag")
            if new_access_rules_tag == NONE_SESSION_TAG:
                new_access_rules_tag = None

            if session.access_rules_tag != new_access_rules_tag:
                session.access_rules_tag = new_access_rules_tag
                session.save()

            # {{{ put together grading rule

            if form.cleaned_data["create_grading_exception"]:
                due = form.cleaned_data["due"]
                if form.cleaned_data["due_same_as_access_expiration"]:
                    due = form.cleaned_data["access_expires"]

                descr = ugettext("Granted excecption")
                if form.cleaned_data["credit_percent"] is not None:
                    descr += string_concat(" (%.1f%% ", ugettext('credit'), ")") \
                            % form.cleaned_data["credit_percent"]

                due_local_naive = due
                if due_local_naive is not None:
                    from relate.utils import as_local_time
                    due_local_naive = (
                            as_local_time(due_local_naive)
                            .replace(tzinfo=None))

                new_grading_rule = {
                    "description": descr,
                    }

                if due_local_naive is not None:
                    new_grading_rule["due"] = due_local_naive
                    new_grading_rule["if_completed_before"] = due_local_naive

                for attr_name in ["credit_percent", "bonus_points",
                        "max_points", "max_points_enforced_cap"]:
                    if form.cleaned_data[attr_name] is not None:
                        new_grading_rule[attr_name] = form.cleaned_data[attr_name]

                if (form.cleaned_data.get("restrict_to_same_tag")
                        and session.access_rules_tag is not None):
                    new_grading_rule["if_has_tag"] = session.access_rules_tag

                if hasattr(grading_rule, "generates_grade"):
                    new_grading_rule["generates_grade"] = \
                            grading_rule.generates_grade

                validate_session_grading_rule(
                        vctx, ugettext("newly created exception"),
                        dict_to_struct(new_grading_rule), tags,
                        grading_rule.grade_identifier)

                fre_grading = FlowRuleException(
                    flow_id=flow_id,
                    participation=participation,
                    creator=pctx.request.user,
                    comment=form.cleaned_data["comment"],
                    kind=flow_rule_kind.grading,
                    rule=new_grading_rule)
                fre_grading.save()

            # }}}

            messages.add_message(pctx.request, messages.SUCCESS,
                    ugettext(
                        "Exception granted to '%(participation)s' "
                        "for '%(flow_id)s'.")
                    % {
                        'participation': participation,
                        'flow_id': flow_id})
            return redirect(
                    "relate-grant_exception",
                    pctx.course.identifier)

    else:
        data = {
                "restrict_to_same_tag": session.access_rules_tag is not None,
                "credit_percent": grading_rule.credit_percent,
                #"due_same_as_access_expiration": True,
                "due": grading_rule.due,
                }
        for perm in access_rule.permissions:
            data[perm] = True

        form = ExceptionStage3Form(data, flow_desc, session.access_rules_tag)

    return render_course_page(pctx, "course/generic-course-form.html", {
        "form": form,
        "form_description": ugettext("Grant Exception"),
        "form_text": string_concat(
            "<div class='well'>",
            ugettext("Granting exception to '%(participation)s' "
            "for '%(flow_id)s' (session %(session)s)."),
            "</div>")
        % {
            'participation': participation,
            'flow_id': flow_id,
            'session': strify_session_for_exception(session)},
    })
Exemple #13
0
    def test_all_day_event(self):
        self.switch_to_fake_commit_sha()

        # lecture 2, no end_time
        lecture2_start_time = datetime.datetime(2019, 1, 1, tzinfo=pytz.UTC)

        self.mock_get_now_or_fake_time.return_value = (
                lecture2_start_time + timedelta(minutes=5))

        lecture2_evt = factories.EventFactory(
            kind=self.default_event_kind, course=self.course,
            all_day=True,
            time=lecture2_start_time, ordinal=2)

        # lecture 3
        lecture3_start_time = lecture2_start_time + timedelta(weeks=1)
        factories.EventFactory(
            kind=self.default_event_kind, course=self.course,
            time=lecture3_start_time, ordinal=3)

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': 1, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-1'})

        # now we add end_time of lecture 2 evt to a time which is not midnight
        lecture2_end_time = lecture2_start_time + timedelta(hours=18)
        lecture2_evt.end_time = lecture2_end_time
        lecture2_evt.save()

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': 1, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-1',
             'end': lecture2_end_time.isoformat()
             })

        # now we update end_time of lecture 2 evt to midnight
        while True:
            local_t = as_local_time(lecture2_end_time)
            end_midnight = datetime.time(tzinfo=local_t.tzinfo)
            if local_t.time() == end_midnight:
                lecture2_evt.end_time = lecture2_end_time
                lecture2_evt.save()
                break

            lecture2_end_time += timedelta(hours=1)

        resp = self.get_course_calendar_view()

        events_json = json.loads(resp.context["events_json"])
        self.assertEqual(len(events_json), 2)

        self.assertDictEqual(
            events_json[1],
            {'id': 1, 'start': lecture2_start_time.isoformat(),
             'allDay': True,
             'title': 'Lecture 2',
             'url': '#event-1',
             'end': lecture2_end_time.isoformat()
             })
Exemple #14
0
def grant_exception_stage_3(pctx, participation_id, flow_id, session_id):
    if pctx.role not in [
            participation_role.instructor,
            participation_role.teaching_assistant]:
        raise PermissionDenied("must be instructor or TA to grant exceptions")

    participation = get_object_or_404(Participation, id=participation_id)

    from course.content import get_flow_desc
    try:
        flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_id,
                pctx.course_commit_sha)
    except ObjectDoesNotExist:
        raise http.Http404()

    session = FlowSession.objects.get(id=int(session_id))

    now_datetime = get_now_or_fake_time(pctx.request)
    from course.utils import (
            get_session_access_rule,
            get_session_grading_rule)
    access_rule = get_session_access_rule(
            session, pctx.role, flow_desc, now_datetime)
    grading_rule = get_session_grading_rule(
            session, pctx.role, flow_desc, now_datetime)

    request = pctx.request
    if request.method == "POST":
        form = ExceptionStage3Form({}, session.access_rules_tag, request.POST)

        from course.constants import flow_rule_kind

        if form.is_valid():
            permissions = [
                    key
                    for key, _ in FLOW_PERMISSION_CHOICES
                    if form.cleaned_data[key]]

            from course.validation import (
                    validate_session_access_rule,
                    validate_session_grading_rule,
                    ValidationContext)
            from relate.utils import dict_to_struct
            vctx = ValidationContext(
                    repo=pctx.repo,
                    commit_sha=pctx.course_commit_sha)

            from course.content import get_flow_desc
            flow_desc = get_flow_desc(pctx.repo,
                    pctx.course,
                    flow_id, pctx.course_commit_sha)
            tags = None
            if hasattr(flow_desc, "rules"):
                tags = getattr(flow_desc.rules, "tags", None)

            # {{{ put together access rule

            new_access_rule = {"permissions": permissions}

            if (form.cleaned_data["restrict_to_same_tag"]
                    and session.access_rules_tag is not None):
                new_access_rule["if_has_tag"] = session.access_rules_tag

            validate_session_access_rule(vctx, "newly created exception",
                    dict_to_struct(new_access_rule), tags)

            fre_access = FlowRuleException(
                flow_id=flow_id,
                participation=participation,
                expiration=form.cleaned_data["access_expires"],
                creator=pctx.request.user,
                comment=form.cleaned_data["comment"],
                kind=flow_rule_kind.access,
                rule=new_access_rule)
            fre_access.save()

            # }}}

            # {{{ put together grading rule

            due = form.cleaned_data["due"]
            if form.cleaned_data["due_same_as_access_expiration"]:
                due = form.cleaned_data["access_expires"]

            descr = "Granted excecption"
            if form.cleaned_data["credit_percent"] is not None:
                descr += " (%.1f%% credit)" % form.cleaned_data["credit_percent"]

            from relate.utils import as_local_time
            new_grading_rule = {
                "credit_percent": form.cleaned_data["credit_percent"],
                "due": as_local_time(due).replace(tzinfo=None),
                "if_completed_before": as_local_time(due).replace(tzinfo=None),
                "description": descr,
                }

            if (form.cleaned_data["restrict_to_same_tag"]
                    and session.access_rules_tag is not None):
                new_grading_rule["if_has_tag"] = session.access_rules_tag

            if hasattr(grading_rule, "grade_identifier"):
                new_grading_rule["grade_identifier"] = \
                        grading_rule.grade_identifier
            if hasattr(grading_rule, "grade_aggregation_strategy"):
                new_grading_rule["grade_aggregation_strategy"] = \
                        grading_rule.grade_aggregation_strategy

            validate_session_grading_rule(vctx, "newly created exception",
                    dict_to_struct(new_grading_rule), tags)

            fre_grading = FlowRuleException(
                flow_id=flow_id,
                participation=participation,
                creator=pctx.request.user,
                comment=form.cleaned_data["comment"],
                kind=flow_rule_kind.grading,
                rule=new_grading_rule)
            fre_grading.save()

            # }}}

            messages.add_message(pctx.request, messages.SUCCESS,
                    "Exception granted to '%s' for '%s'." % (participation, flow_id))
            return redirect(
                    "course.views.grant_exception",
                    pctx.course.identifier)

    else:
        data = {
                "restrict_to_same_tag": session.access_rules_tag is not None,
                "credit_percent": grading_rule.credit_percent,
                #"due_same_as_access_expiration": True,
                "due": grading_rule.due,
                }
        for perm in access_rule.permissions:
            data[perm] = True

        form = ExceptionStage3Form(data, session.access_rules_tag)

    return render_course_page(pctx, "course/generic-course-form.html", {
        "form": form,
        "form_description": "Grant Exception",
        "form_text": "<div class='well'>Granting exception to '%s' for '%s'.</div>"
        % (participation, flow_id),
    })