Beispiel #1
0
def expire_flow_session(fctx, flow_session, grading_rule, now_datetime, past_due_only=False):
    if not flow_session.in_progress:
        raise RuntimeError(_("Can't expire a session that's not in progress"))
    if flow_session.participation is None:
        raise RuntimeError(_("Can't expire an anonymous flow session"))

    assert isinstance(grading_rule, FlowSessionGradingRule)

    if past_due_only and grading_rule.due is not None and now_datetime < grading_rule.due:
        return False

    if flow_session.expiration_mode == flow_session_expiration_mode.roll_over:
        session_start_rule = get_session_start_rule(
            flow_session.course,
            flow_session.participation,
            flow_session.participation.role,
            flow_session.flow_id,
            fctx.flow_desc,
            now_datetime,
            for_rollover=True,
        )

        if not session_start_rule.may_start_new_session:
            # No new session allowed: finish.
            return finish_flow_session(fctx, flow_session, grading_rule, now_datetime=now_datetime)

        flow_session.access_rules_tag = session_start_rule.tag_session

        access_rule = get_session_access_rule(
            flow_session, flow_session.participation.role, fctx.flow_desc, now_datetime
        )

        if not is_expiration_mode_allowed(flow_session.expiration_mode, access_rule.permissions):
            flow_session.expiration_mode = flow_session_expiration_mode.end
        flow_session.save()

        return True

    elif flow_session.expiration_mode == flow_session_expiration_mode.end:
        return finish_flow_session(fctx, flow_session, grading_rule, now_datetime=now_datetime)
    else:
        raise ValueError(
            _("invalid expiration mode '%(mode)s' on flow session ID " "%(session_id)d")
            % {"mode": flow_session.expiration_mode, "session_id": flow_session.id}
        )
Beispiel #2
0
def grant_exception_stage_2(pctx, participation_id, flow_id):
    # type: (CoursePageContext, Text, Text) -> http.HttpResponse

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

    # {{{ get flow data

    participation = get_object_or_404(Participation, id=participation_id)

    form_text = (string_concat(
        "<div class='well'>",
        ugettext("Granting exception to '%(participation)s' for "
                 "'%(flow_id)s'."), "</div>") % {
                     'participation': participation,
                     'flow_id': flow_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()

    now_datetime = get_now_or_fake_time(pctx.request)

    if hasattr(flow_desc, "rules"):
        access_rules_tags = getattr(flow_desc.rules, "tags", [])
    else:
        access_rules_tags = []

    NONE_SESSION_TAG = string_concat("<<<", _("NONE"), ">>>")  # noqa
    session_tag_choices = [(tag, tag) for tag in access_rules_tags] + [
        (NONE_SESSION_TAG, string_concat("(", _("NONE"), ")"))
    ]

    from course.utils import get_session_start_rule
    session_start_rule = get_session_start_rule(pctx.course, participation,
                                                flow_id, flow_desc,
                                                now_datetime)

    create_session_is_override = False
    if not session_start_rule.may_start_new_session:
        create_session_is_override = True
        form_text += (
            "<div class='alert alert-info'>%s</div>" % (string_concat(
                "<i class='fa fa-info-circle'></i> ",
                _("Creating a new session is (technically) not allowed "
                  "by course rules. Clicking 'Create Session' anyway will "
                  "override this rule."))))

    default_tag = session_start_rule.tag_session
    if default_tag is None:
        default_tag = NONE_SESSION_TAG

    # }}}

    def find_sessions():
        # type: () -> List[FlowSession]

        return list(
            FlowSession.objects.filter(participation=participation,
                                       flow_id=flow_id).order_by("start_time"))

    exception_form = None
    request = pctx.request
    if request.method == "POST":
        exception_form = ExceptionStage2Form(find_sessions(), request.POST)
        create_session_form = CreateSessionForm(session_tag_choices,
                                                default_tag,
                                                create_session_is_override,
                                                request.POST)

        if "create_session" in request.POST or "next" in request.POST:
            pass
        else:
            raise SuspiciousOperation(_("invalid command"))

        if create_session_form.is_valid() and "create_session" in request.POST:
            from course.flow import start_flow

            access_rules_tag = (
                create_session_form.
                cleaned_data["access_rules_tag_for_new_session"])
            if access_rules_tag == NONE_SESSION_TAG:
                access_rules_tag = None

            start_flow(pctx.repo,
                       pctx.course,
                       participation,
                       user=participation.user,
                       flow_id=flow_id,
                       flow_desc=flow_desc,
                       session_start_rule=session_start_rule,
                       now_datetime=now_datetime)

            exception_form = None

        elif exception_form.is_valid(
        ) and "next" in request.POST:  # type: ignore
            return redirect(
                "relate-grant_exception_stage_3", pctx.course.identifier,
                participation.id, flow_id,
                exception_form.cleaned_data["session"])  # type: ignore
    else:
        create_session_form = CreateSessionForm(session_tag_choices,
                                                default_tag,
                                                create_session_is_override)

    if exception_form is None:
        exception_form = ExceptionStage2Form(find_sessions())

    return render_course_page(
        pctx, "course/generic-course-form.html", {
            "forms": [exception_form, create_session_form],
            "form_text": form_text,
            "form_description": _("Grant Exception"),
        })
Beispiel #3
0
def grant_exception_stage_2(pctx, participation_id, flow_id):
    # type: (CoursePageContext, Text, Text) -> http.HttpResponse

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

    # {{{ get flow data

    participation = get_object_or_404(Participation, id=participation_id)

    form_text = (
            string_concat(
                "<div class='well'>",
                ugettext("Granting exception to '%(participation)s' for "
                "'%(flow_id)s'."),
                "</div>")
            % {
                'participation': participation,
                'flow_id': flow_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()

    now_datetime = get_now_or_fake_time(pctx.request)

    if hasattr(flow_desc, "rules"):
        access_rules_tags = getattr(flow_desc.rules, "tags", [])
    else:
        access_rules_tags = []

    NONE_SESSION_TAG = string_concat("<<<", _("NONE"), ">>>")  # noqa
    session_tag_choices = [
            (tag, tag)
            for tag in access_rules_tags] + [(NONE_SESSION_TAG,
                    string_concat("(", _("NONE"), ")"))]

    from course.utils import get_session_start_rule
    session_start_rule = get_session_start_rule(pctx.course, participation,
            flow_id, flow_desc, now_datetime)

    create_session_is_override = False
    if not session_start_rule.may_start_new_session:
        create_session_is_override = True
        form_text += ("<div class='alert alert-info'>%s</div>" % (
            string_concat(
                "<i class='fa fa-info-circle'></i> ",
                _("Creating a new session is (technically) not allowed "
                "by course rules. Clicking 'Create Session' anyway will "
                "override this rule."))))

    default_tag = session_start_rule.tag_session
    if default_tag is None:
        default_tag = NONE_SESSION_TAG

    # }}}

    def find_sessions():
        # type: () -> List[FlowSession]

        return list(FlowSession.objects
                .filter(
                    participation=participation,
                    flow_id=flow_id)
               .order_by("start_time"))

    exception_form = None
    request = pctx.request
    if request.method == "POST":
        exception_form = ExceptionStage2Form(find_sessions(), request.POST)
        create_session_form = CreateSessionForm(
                session_tag_choices, default_tag, create_session_is_override,
                request.POST)

        if "create_session" in request.POST or "next" in request.POST:
            pass
        else:
            raise SuspiciousOperation(_("invalid command"))

        if create_session_form.is_valid() and "create_session" in request.POST:
            from course.flow import start_flow

            access_rules_tag = (
                    create_session_form.cleaned_data[
                        "access_rules_tag_for_new_session"])
            if access_rules_tag == NONE_SESSION_TAG:
                access_rules_tag = None

            start_flow(pctx.repo, pctx.course, participation,
                    user=participation.user,
                    flow_id=flow_id,
                    flow_desc=flow_desc,
                    session_start_rule=session_start_rule,
                    now_datetime=now_datetime)

            exception_form = None

        elif exception_form.is_valid() and "next" in request.POST:  # type: ignore
            return redirect(
                    "relate-grant_exception_stage_3",
                    pctx.course.identifier,
                    participation.id,
                    flow_id,
                    exception_form.cleaned_data["session"])  # type: ignore
    else:
        create_session_form = CreateSessionForm(
                session_tag_choices, default_tag, create_session_is_override)

    if exception_form is None:
        exception_form = ExceptionStage2Form(find_sessions())

    return render_course_page(pctx, "course/generic-course-form.html", {
        "forms": [exception_form, create_session_form],
        "form_text": form_text,
        "form_description": _("Grant Exception"),
    })
Beispiel #4
0
def view_start_flow(pctx, flow_id):
    request = pctx.request

    now_datetime = get_now_or_fake_time(request)
    fctx = FlowContext(pctx.repo, pctx.course, flow_id, participation=pctx.participation)

    session_start_rule = get_session_start_rule(
        pctx.course,
        pctx.participation,
        pctx.role,
        flow_id,
        fctx.flow_desc,
        now_datetime,
        remote_address=pctx.remote_address,
    )

    if request.method == "POST":
        if "start" in request.POST:

            if not session_start_rule.may_start_new_session:
                raise PermissionDenied(_("new session not allowed"))

            session = start_flow(
                pctx.repo,
                pctx.course,
                pctx.participation,
                flow_id,
                fctx.flow_desc,
                access_rules_tag=session_start_rule.tag_session,
                now_datetime=now_datetime,
            )

            return redirect("relate-view_flow_page", pctx.course.identifier, session.id, 0)

        else:
            raise SuspiciousOperation(_("unrecognized POST action"))

    else:
        if session_start_rule.may_list_existing_sessions:
            past_sessions = FlowSession.objects.filter(
                participation=pctx.participation, flow_id=fctx.flow_id, participation__isnull=False
            ).order_by("start_time")

            from collections import namedtuple

            SessionProperties = namedtuple(
                "SessionProperties", ["may_view", "may_modify", "due", "grade_description"]  # noqa
            )

            past_sessions_and_properties = []
            for session in past_sessions:
                access_rule = get_session_access_rule(
                    session, pctx.role, fctx.flow_desc, now_datetime, remote_address=pctx.remote_address
                )
                grading_rule = get_session_grading_rule(session, pctx.role, fctx.flow_desc, now_datetime)

                session_properties = SessionProperties(
                    may_view=flow_permission.view in access_rule.permissions,
                    may_modify=(
                        flow_permission.submit_answer in access_rule.permissions
                        or flow_permission.end_session in access_rule.permissions
                    ),
                    due=grading_rule.due,
                    grade_description=grading_rule.description,
                )
                past_sessions_and_properties.append((session, session_properties))
        else:
            past_sessions_and_properties = []

        may_start = session_start_rule.may_start_new_session
        potential_session = FlowSession(
            course=pctx.course,
            participation=pctx.participation,
            flow_id=flow_id,
            in_progress=True,
            expiration_mode=flow_session_expiration_mode.end,
            access_rules_tag=session_start_rule.tag_session,
        )

        new_session_grading_rule = get_session_grading_rule(potential_session, pctx.role, fctx.flow_desc, now_datetime)

        start_may_decrease_grade = bool(
            past_sessions_and_properties
        ) and new_session_grading_rule.grade_aggregation_strategy not in [
            None,
            grade_aggregation_strategy.max_grade,
            grade_aggregation_strategy.use_earliest,
        ]

        return render_course_page(
            pctx,
            "course/flow-start.html",
            {
                "flow_desc": fctx.flow_desc,
                "flow_identifier": flow_id,
                "now": now_datetime,
                "may_start": may_start,
                "new_session_grading_rule": new_session_grading_rule,
                "grade_aggregation_strategy_descr": (
                    dict(GRADE_AGGREGATION_STRATEGY_CHOICES).get(new_session_grading_rule.grade_aggregation_strategy)
                ),
                "start_may_decrease_grade": start_may_decrease_grade,
                "past_sessions_and_properties": past_sessions_and_properties,
            },
            allow_instant_flow_requests=False,
        )
Beispiel #5
0
def grant_exception_stage_2(pctx, participation_id, flow_id):
    if pctx.role not in [
            participation_role.instructor,
            participation_role.teaching_assistant]:
        raise PermissionDenied("must be instructor or TA to grant exceptions")

    # {{{ get flow data

    participation = get_object_or_404(Participation, id=participation_id)

    form_text = ("<div class='well'>Granting exception to '%s' for '%s'.</div>"
        % (participation, flow_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()

    now_datetime = get_now_or_fake_time(pctx.request)

    if hasattr(flow_desc, "rules"):
        access_rules_tags = getattr(flow_desc.rules, "tags", [])
    else:
        access_rules_tags = []

    NONE_SESSION_TAG = "<<<NONE>>>"
    session_tag_choices = [
            (tag, tag)
            for tag in access_rules_tags] + [(NONE_SESSION_TAG, "(None)")]

    from course.utils import get_session_start_rule
    session_start_rule = get_session_start_rule(pctx.course, participation,
            participation.role, flow_id, flow_desc, now_datetime)

    create_session_is_override = False
    if not session_start_rule.may_start_new_session:
        create_session_is_override = True
        form_text += ("<div class='alert alert-info'>%s</div>"
            % "Creating a new session is (technically) not allowed by course "
                "rules. Clicking 'Create Session' anyway will override this rule.")

    default_tag = session_start_rule.tag_session
    if default_tag is None:
        default_tag = NONE_SESSION_TAG

    # }}}

    def find_sessions():
        return (FlowSession.objects
                .filter(
                    participation=participation,
                    flow_id=flow_id)
               .order_by("start_time"))

    form = None
    request = pctx.request
    if request.method == "POST":
        form = ExceptionStage2Form(
                session_tag_choices, default_tag, create_session_is_override,
                find_sessions(), request.POST)

        if "create_session" in request.POST or "next" in request.POST:
            pass
        else:
            raise SuspiciousOperation("invalid command")

        if form.is_valid() and "create_session" in request.POST:
            from course.flow import start_flow

            access_rules_tag = form.cleaned_data["access_rules_tag_for_new_session"]
            if access_rules_tag == NONE_SESSION_TAG:
                access_rules_tag = None

            start_flow(pctx.repo, pctx.course, participation, flow_id,
                    flow_desc=flow_desc,
                    access_rules_tag=access_rules_tag,
                    now_datetime=now_datetime)

            form = None

        elif form.is_valid() and "next" in request.POST:
            return redirect(
                    "course.views.grant_exception_stage_3",
                    pctx.course.identifier,
                    participation.id,
                    flow_id,
                    form.cleaned_data["session"])

    if form is None:
        form = ExceptionStage2Form(session_tag_choices, default_tag,
                create_session_is_override, find_sessions())

    return render_course_page(pctx, "course/generic-course-form.html", {
        "form": form,
        "form_text": form_text,
        "form_description": "Grant Exception",
    })