Пример #1
0
def grade_page_visits(fctx, flow_session, answer_visits, force_regrade=False):
    for i in range(len(answer_visits)):
        answer_visit = answer_visits[i]

        if answer_visit is not None:
            answer_visit.is_graded_answer = True
            answer_visit.save()

        else:
            page_data = flow_session.page_data.get(ordinal=i)
            page = instantiate_flow_page_with_ctx(fctx, page_data)

            if not page.expects_answer():
                continue

            # Create a synthetic visit to attach a grade
            answer_visit = FlowPageVisit()
            answer_visit.flow_session = flow_session
            answer_visit.page_data = page_data
            answer_visit.is_synthetic = True
            answer_visit.answer = None
            answer_visit.is_graded_answer = True
            answer_visit.save()

            answer_visits[i] = answer_visit

        if (answer_visit is not None
                and (not answer_visit.grades.count() or force_regrade)):
            grade_page_visit(answer_visit,
                    graded_at_git_commit_sha=fctx.flow_commit_sha)
Пример #2
0
def grade_page_visits(fctx, flow_session, answer_visits):
    for i in range(len(answer_visits)):
        answer_visit = answer_visits[i]

        if answer_visit is not None:
            answer_visit.is_graded_answer = True
            answer_visit.save()

        else:
            page_data = flow_session.page_data.get(ordinal=i)
            page = instantiate_flow_page_with_ctx(fctx, page_data)

            if not page.expects_answer():
                continue

            # Create a synthetic visit to attach a grade
            answer_visit = FlowPageVisit()
            answer_visit.flow_session = flow_session
            answer_visit.page_data = page_data
            answer_visit.is_synthetic = True
            answer_visit.answer = None
            answer_visit.is_graded_answer = True
            answer_visit.save()

            answer_visits[i] = answer_visit

        if answer_visit is not None:
            grade_page_visit(answer_visit)
Пример #3
0
def view_flow_page(pctx, flow_identifier, ordinal):
    request = pctx.request

    flow_session = find_current_flow_session(request, flow_identifier)

    if flow_session is None:
        messages.add_message(request, messages.WARNING,
                "No in-progress session record found for this flow. "
                "Redirected to flow start page.")

        return redirect("course.flow.start_flow",
                pctx.course.identifier,
                flow_identifier)

    fpctx = FlowPageContext(pctx.repo, pctx.course, flow_identifier, ordinal,
            participation=pctx.participation,
            flow_session=flow_session)

    if fpctx.page_desc is None:
        messages.add_message(request, messages.ERROR,
                "Your session does not match the course content and needs "
                "to be reset. Course staff have been notified about this issue. "
                "Please get in touch with them to get help.")

        from django.template.loader import render_to_string
        message = render_to_string("course/session-mismatch.txt", {
            "page_data": fpctx.page_data,
            "course": pctx.course,
            "user": pctx.request.user,
            })

        from django.core.mail import send_mail
        from django.conf import settings
        send_mail("[%s] session mismatch with course content"
                % pctx.course.identifier,
                message,
                settings.ROBOT_EMAIL_FROM,
                recipient_list=[pctx.course.email])

        return redirect("course.flow.start_flow",
                pctx.course.identifier,
                flow_identifier)

    current_access_rule = fpctx.get_current_access_rule(
            flow_session, pctx.role, pctx.participation,
            get_now_or_fake_time(request))

    page_context = fpctx.page_context
    page_data = fpctx.page_data

    if flow_permission.view not in current_access_rule.permissions:
        raise PermissionDenied("not allowed to view flow")

    if request.method == "POST":
        if "finish" in request.POST:
            return redirect("course.flow.finish_flow_session_view",
                    pctx.course.identifier, flow_identifier)
        else:
            # reject answer update if flow is not in-progress
            if not flow_session.in_progress:
                raise PermissionDenied("session is not in progress")

            # reject if previous answer was final
            if (fpctx.prev_answer_visit is not None
                    and fpctx.prev_answer_visit.is_graded_answer
                    and flow_permission.change_answer
                        not in current_access_rule.permissions):
                raise PermissionDenied("already have final answer")

            form, form_html = fpctx.page.post_form(
                    fpctx.page_context, fpctx.page_data.data,
                    post_data=request.POST, files_data=request.POST)

            pressed_button = get_pressed_button(form)

            if form.is_valid():
                # {{{ form validated, process answer

                messages.add_message(request, messages.INFO,
                        "Answer saved.")

                page_visit = FlowPageVisit()
                page_visit.flow_session = flow_session
                page_visit.page_data = fpctx.page_data
                page_visit.remote_address = request.META['REMOTE_ADDR']

                page_visit.answer = fpctx.page.answer_data(
                        fpctx.page_context, fpctx.page_data.data,
                        form)
                page_visit.is_graded_answer = pressed_button == "submit"
                page_visit.save()

                answer_was_graded = page_visit.is_graded_answer
                may_change_answer = (
                    not answer_was_graded
                    or flow_permission.change_answer
                    in current_access_rule.permissions)

                feedback = fpctx.page.grade(
                        page_context, page_data.data, page_visit.answer,
                        grade_data=None)

                if page_visit.is_graded_answer:
                    grade = FlowPageVisitGrade()
                    grade.visit = page_visit
                    grade.max_points = fpctx.page.max_points(page_data.data)
                    grade.graded_at_git_commit_sha = fpctx.flow_commit_sha

                    if feedback is not None:
                        grade.correctness = feedback.correctness
                        grade.feedback = feedback.as_json()

                    grade.save()

                    del grade

                if (pressed_button == "save_and_next"
                        and not will_receive_feedback(
                            current_access_rule.permissions)):
                    return redirect("course.flow.view_flow_page",
                            pctx.course.identifier,
                            flow_identifier,
                            fpctx.ordinal + 1)
                elif (pressed_button == "save_and_finish"
                        and not will_receive_feedback(
                            current_access_rule.permissions)):
                    return redirect("course.flow.finish_flow_session_view",
                            pctx.course.identifier, flow_identifier)
                else:
                    form, form_html = fpctx.page.make_form(
                            page_context, page_data.data,
                            page_visit.answer, not may_change_answer)

                    # continue at common flow page generation below

                # }}}

                del page_visit

            else:
                # form did not validate
                create_flow_page_visit(request, flow_session, fpctx.page_data)

                answer_was_graded = False
                may_change_answer = True
                # because we were allowed this far in by the check above

                feedback = None

                # continue at common flow page generation below

    else:
        create_flow_page_visit(request, flow_session, fpctx.page_data)

        if fpctx.prev_answer_visit is not None:
            answer_was_graded = fpctx.prev_answer_visit.is_graded_answer
        else:
            answer_was_graded = False

        may_change_answer = (
                (not answer_was_graded
                    or (flow_permission.change_answer
                        in current_access_rule.permissions))

                # can happen if no answer was ever saved
                and flow_session.in_progress)

        if fpctx.page.expects_answer():
            if fpctx.prev_answer_visit is not None:
                answer_data = fpctx.prev_answer_visit.answer
                feedback = fpctx.prev_answer_visit.get_most_recent_feedback()
            else:
                answer_data = None
                feedback = None

            form, form_html = fpctx.page.make_form(
                    page_context, page_data.data,
                    answer_data, not may_change_answer)
        else:
            form = None
            form_html = None
            feedback = None

    # start common flow page generation

    # defined at this point:
    # form, form_html, may_change_answer, answer_was_graded, feedback

    if form is not None and may_change_answer:
        form = add_buttons_to_form(form, fpctx, flow_session,
                current_access_rule.permissions)

    show_correctness = None
    show_answer = None

    shown_feedback = None

    if fpctx.page.expects_answer() and answer_was_graded:
        show_correctness = (
                flow_permission.see_correctness in current_access_rule.permissions
                or (
                    (flow_permission.see_correctness_after_completion
                        in current_access_rule.permissions)
                    and not flow_session.in_progress))

        show_answer = flow_permission.see_answer in current_access_rule.permissions

        if show_correctness or show_answer:
            shown_feedback = feedback

    title = fpctx.page.title(page_context, page_data.data)
    body = fpctx.page.body(page_context, page_data.data)

    # {{{ render flow page

    if form is not None and form_html is None:
        from crispy_forms.utils import render_crispy_form
        from django.template import RequestContext
        context = RequestContext(request, {})
        form_html = render_crispy_form(form, context=context)
        del context

    args = {
        "flow_identifier": fpctx.flow_identifier,
        "flow_desc": fpctx.flow_desc,
        "ordinal": fpctx.ordinal,
        "page_data": fpctx.page_data,
        "percentage": int(100*(fpctx.ordinal+1) / flow_session.page_count),
        "flow_session": flow_session,

        "title": title, "body": body,
        "form": form,
        "form_html": form_html,
        "feedback": shown_feedback,
        "show_correctness": show_correctness,
        "may_change_answer": may_change_answer,
        "will_receive_feedback":
        will_receive_feedback(current_access_rule.permissions),
        "show_answer": show_answer,
    }

    if fpctx.page.expects_answer():
        args["max_points"] = fpctx.page.max_points(fpctx.page_data)

    return render_course_page(
            pctx, "course/flow-page.html", args,
            allow_instant_flow_requests=False)
Пример #4
0
def view_flow_page(request, course_identifier, flow_identifier, ordinal):
    flow_session = find_current_flow_session(request, flow_identifier)

    if flow_session is None:
        messages.add_message(request, messages.WARNING,
                "No in-progress session record found for this flow. "
                "Redirected to flow start page.")

        return redirect("course.flow.start_flow",
                course_identifier,
                flow_identifier)

    fpctx = FlowPageContext(request, course_identifier, flow_identifier,
            ordinal, flow_session)

    page_context = fpctx.page_context
    page_data = fpctx.page_data

    if flow_permission.view not in fpctx.permissions:
        raise PermissionDenied("not allowed to view flow")

    if request.method == "POST":
        if "finish" in request.POST:
            return redirect("course.flow.finish_flow_session_view",
                    course_identifier, flow_identifier)
        else:
            # reject answer update if flow is not in-progress
            if not flow_session.in_progress:
                raise PermissionDenied("session is not in progress")

            # reject if previous answer was final
            if (fpctx.prev_answer_visit is not None
                    and fpctx.prev_answer_visit.is_graded_answer
                    and flow_permission.change_answer not in fpctx.permissions):
                raise PermissionDenied("already have final answer")

            form, form_html = fpctx.page.post_form(
                    fpctx.page_context, fpctx.page_data.data,
                    post_data=request.POST, files_data=request.POST)

            pressed_button = get_pressed_button(form)

            if form.is_valid():
                # {{{ form validated, process answer

                messages.add_message(request, messages.INFO,
                        "Answer saved.")

                page_visit = FlowPageVisit()
                page_visit.flow_session = fpctx.flow_session
                page_visit.page_data = fpctx.page_data
                page_visit.remote_address = request.META['REMOTE_ADDR']

                page_visit.answer = fpctx.page.answer_data(
                        fpctx.page_context, fpctx.page_data.data,
                        form)
                page_visit.is_graded_answer = pressed_button == "submit"
                page_visit.save()

                answer_was_graded = page_visit.is_graded_answer
                may_change_answer = (
                        not answer_was_graded
                        or flow_permission.change_answer in fpctx.permissions)

                feedback = fpctx.page.grade(
                        page_context, page_data.data, page_visit.answer,
                        grade_data=None)

                if page_visit.is_graded_answer:
                    grade = FlowPageVisitGrade()
                    grade.visit = page_visit
                    grade.max_points = fpctx.page.max_points(page_data.data)

                    if feedback is not None:
                        grade.correctness = feedback.correctness
                        grade.feedback = feedback.as_json()

                    grade.save()

                    del grade

                if (pressed_button == "save_and_next"
                        and not fpctx.will_receive_feedback()):
                    return redirect("course.flow.view_flow_page",
                            course_identifier,
                            flow_identifier,
                            fpctx.ordinal + 1)
                elif (pressed_button == "save_and_finish"
                        and not fpctx.will_receive_feedback()):
                    return redirect("course.flow.finish_flow_session_view",
                            course_identifier, flow_identifier)
                else:
                    form, form_html = fpctx.page.make_form(
                            page_context, page_data.data,
                            page_visit.answer, not may_change_answer)

                    # continue at common flow page generation below

                # }}}

                del page_visit

            else:
                # form did not validate

                fpctx.create_visit(request)

                answer_was_graded = False
                may_change_answer = True
                # because we were allowed this far in by the check above

                feedback = None

                # continue at common flow page generation below

    else:
        fpctx.create_visit(request)

        if fpctx.prev_answer_visit is not None:
            answer_was_graded = fpctx.prev_answer_visit.is_graded_answer
        else:
            answer_was_graded = False

        may_change_answer = (
                (not answer_was_graded
                    or flow_permission.change_answer in fpctx.permissions)

                # can happen if no answer was ever saved
                and fpctx.flow_session.in_progress)

        if fpctx.page.expects_answer():
            if fpctx.prev_answer_visit is not None:
                answer_data = fpctx.prev_answer_visit.answer
                feedback = fpctx.prev_answer_visit.get_most_recent_feedback()
            else:
                answer_data = None
                feedback = None

            form, form_html = fpctx.page.make_form(
                    page_context, page_data.data,
                    answer_data, not may_change_answer)
        else:
            form = None
            form_html = None
            feedback = None

    # start common flow page generation

    # defined at this point:
    # form, form_html, may_change_answer, answer_was_graded, feedback

    if form is not None and may_change_answer:
        form = add_buttons_to_form(fpctx, form)

    show_correctness = None
    show_answer = None

    shown_feedback = None

    if fpctx.page.expects_answer() and answer_was_graded:
        show_correctness = flow_permission.see_correctness in fpctx.permissions
        show_answer = flow_permission.see_answer in fpctx.permissions

        if show_correctness or show_answer:
            shown_feedback = feedback

    title = fpctx.page.title(page_context, page_data.data)
    body = fpctx.page.body(page_context, page_data.data)

    # {{{ render flow page

    if form is not None and form_html is None:
        from crispy_forms.utils import render_crispy_form
        from django.template import RequestContext
        context = RequestContext(request, {})
        form_html = render_crispy_form(form, context=context)
        del context

    args = {
        "course": fpctx.course,
        "course_desc": fpctx.course_desc,
        "flow_identifier": fpctx.flow_identifier,
        "flow_desc": fpctx.flow_desc,
        "ordinal": fpctx.ordinal,
        "page_data": fpctx.page_data,
        "percentage": fpctx.percentage_done,
        "flow_session": fpctx.flow_session,
        "participation": fpctx.participation,

        "role": fpctx.role,
        "participation_role": participation_role,

        "title": title, "body": body,
        "form": form,
        "form_html": form_html,
        "feedback": shown_feedback,
        "show_correctness": show_correctness,
        "may_change_answer": may_change_answer,
        "will_receive_feedback": fpctx.will_receive_feedback(),
        "show_answer": show_answer,
    }

    if fpctx.page.expects_answer():
        args["max_points"] = fpctx.page.max_points(fpctx.page_data)

    return render(request, "course/flow-page.html", args)