Newer
Older
return redirect("relate-view_start_flow",
pctx.course.identifier,
try:
fpctx = FlowPageContext(pctx.repo, pctx.course, flow_id, ordinal,
participation=pctx.participation,
flow_session=flow_session)
except PageOrdinalOutOfRange:
return redirect("relate-view_flow_page",
pctx.course.identifier,
flow_session.id,
flow_session.page_count-1)
access_rule = get_session_access_rule(
flow_session, pctx.role, fpctx.flow_desc, get_now_or_fake_time(request),
pctx.remote_address)
permissions = fpctx.page.get_modified_permissions_for_page(
access_rule.permissions)
if access_rule.message:
messages.add_message(request, messages.INFO, access_rule.message)
page_context = fpctx.page_context
page_data = fpctx.page_data
answer_data = None
grade_data = None
if flow_permission.view not in permissions:
raise PermissionDenied(_("not allowed to view flow"))
if request.method == "POST":
if "finish" in request.POST:
return redirect("relate-finish_flow_session_view",
pctx.course.identifier, flow_session_id)
submission_allowed = True
# reject answer update if permission not present
if flow_permission.submit_answer not in permissions:
messages.add_message(request, messages.ERROR,
# reject if previous answer was final
if (fpctx.prev_answer_visit is not None
and fpctx.prev_answer_visit.is_submitted_answer
and flow_permission.change_answer
messages.add_message(request, messages.ERROR,
page_behavior = get_page_behavior(
page=fpctx.page,
permissions=permissions,
session_in_progress=flow_session.in_progress,
answer_was_graded=False)
form = fpctx.page.process_form_post(
post_data=request.POST, files_data=request.FILES,
page_behavior=page_behavior)
pressed_button = get_pressed_button(form)
if submission_allowed and form.is_valid():
# {{{ form validated, process answer
messages.add_message(request, messages.INFO,
page_visit = FlowPageVisit()
page_visit.flow_session = flow_session
page_visit.page_data = fpctx.page_data
page_visit.remote_address = request.META['REMOTE_ADDR']
answer_data = page_visit.answer = fpctx.page.answer_data(
fpctx.page_context, fpctx.page_data.data,
form, request.FILES)
page_visit.is_submitted_answer = pressed_button == "submit"
answer_was_graded = page_visit.is_submitted_answer
page_behavior = get_page_behavior(
page=fpctx.page,
permissions=permissions,
session_in_progress=flow_session.in_progress,
answer_was_graded=answer_was_graded)
if fpctx.page.is_answer_gradable():
feedback = fpctx.page.grade(
page_context, page_data.data, page_visit.answer,
grade_data=None)
if page_visit.is_submitted_answer:
grade = FlowPageVisitGrade()
grade.visit = page_visit
grade.max_points = fpctx.page.max_points(page_data.data)
grade.graded_at_git_commit_sha = pctx.course_commit_sha
bulk_feedback_json = None
if feedback is not None:
grade.correctness = feedback.correctness
grade.feedback, bulk_feedback_json = feedback.as_json()
update_bulk_feedback(page_data, grade, bulk_feedback_json)
del grade
else:
feedback = None
if (pressed_button == "save_and_next"
and not will_receive_feedback(permissions)):
return redirect("relate-view_flow_page",
pctx.course.identifier,
fpctx.ordinal + 1)
elif (pressed_button == "save_and_finish"
and not will_receive_feedback(permissions)):
return redirect("relate-finish_flow_session_view",
pctx.course.identifier, flow_session_id)
# The form needs to be recreated here, although there
# already is a form from the process_form_post above. This
# is because the value of 'answer_was_graded' may have
# changed between then and now (and page_behavior with
# it)--and that value depends on form validity, which we
# can only decide once we have a form.
form = fpctx.page.make_form(
answer_data, page_behavior)
# 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
if fpctx.prev_answer_visit is not None:
answer_data = fpctx.prev_answer_visit.answer
feedback = None
messages.add_message(request, messages.ERROR,
_("Failed to submit answer."))
# 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_submitted_answer
else:
answer_was_graded = False
page_behavior = get_page_behavior(
page=fpctx.page,
permissions=permissions,
session_in_progress=flow_session.in_progress,
answer_was_graded=answer_was_graded)
if fpctx.prev_answer_visit is not None:
answer_data = fpctx.prev_answer_visit.answer
most_recent_grade = fpctx.prev_answer_visit.get_most_recent_grade()
if most_recent_grade is not None:
feedback = get_feedback_for_grade(most_recent_grade)
grade_data = most_recent_grade.grade_data
else:
feedback = None
grade_data = None
else:
feedback = None
form = fpctx.page.make_form(
page_context, page_data.data,
answer_data, page_behavior)
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 page_behavior.may_change_answer:
form = add_buttons_to_form(form, fpctx, flow_session,
shown_feedback = None
if (fpctx.page.expects_answer() and answer_was_graded
and (
page_behavior.show_correctness
or page_behavior.show_answer)):
shown_feedback = feedback
title = fpctx.page.title(page_context, page_data.data)
body = fpctx.page.body(page_context, page_data.data)
if page_behavior.show_answer:
correct_answer = fpctx.page.correct_answer(
page_context, page_data.data,
answer_data, grade_data)
else:
correct_answer = None
if (
flow_session.participation is None
and
fpctx.page.expects_answer()
):
messages.add_message(request, messages.WARNING,
_("<p><b>WARNING!</b> What you enter on this page will not be "
"associated with your user account, likely because "
"you have not completed your enrollment in this course. "
"Any data you enter here will not be retrievable later "
"and will not be graded. If this is not what you intended, "
"save your work on this session now (outside of RELATE), "
"complete your enrollment in this course in RELATE, "
"and restart your work on this flow.</p>"
"<p> To confirm that you've "
"completed your enrollment, make sure there is no 'Sign in' "
"or 'Enroll' button at the top of the main course page.<p>"
"<p><b>In addition, you should immediately bookmark this page "
"to ensure you'll be able to return to your work.</b>"))
if form is not None:
form_html = fpctx.page.form_to_html(
pctx.request, page_context, form, answer_data)
else:
form_html = None
expiration_mode_choices = []
for key, descr in FLOW_SESSION_EXPIRATION_MODE_CHOICES:
if is_expiration_mode_allowed(key, permissions):
expiration_mode_choices.append((key, descr))
"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,
"page_numbers": zip(
range(flow_session.page_count),
range(1, flow_session.page_count+1)),
"feedback": shown_feedback,
"correct_answer": correct_answer,
"show_correctness": page_behavior.show_correctness,
"may_change_answer": page_behavior.may_change_answer,
"may_change_graded_answer": (
(flow_permission.change_answer
and flow_session.in_progress),
"will_receive_feedback": will_receive_feedback(permissions),
"show_answer": page_behavior.show_answer,
"expiration_mode_choices": expiration_mode_choices,
"expiration_mode_choice_count": len(expiration_mode_choices),
"expiration_mode": flow_session.expiration_mode,
if fpctx.page.expects_answer() and fpctx.page.is_answer_gradable():
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)
@course_view
def update_expiration_mode(pctx, flow_session_id):
if pctx.request.method != "POST":
raise SuspiciousOperation(_("only POST allowed"))
flow_session = get_object_or_404(FlowSession, id=flow_session_id)
if flow_session.participation != pctx.participation:
raise PermissionDenied(
_("may only change your own flow sessions"))
if not flow_session.in_progress:
raise PermissionDenied(
_("may only change in-progress flow sessions"))
expmode = pctx.request.POST.get("expiration_mode")
if not any(expmode == em_key
for em_key, _ in FLOW_SESSION_EXPIRATION_MODE_CHOICES):
raise SuspiciousOperation(_("invalid expiration mode"))
fctx = FlowContext(pctx.repo, pctx.course, flow_session.flow_id,
participation=pctx.participation,
flow_session=flow_session)
access_rule = get_session_access_rule(
flow_session, pctx.role, fctx.flow_desc,
get_now_or_fake_time(pctx.request),
pctx.remote_address)
if is_expiration_mode_allowed(expmode, access_rule.permissions):
flow_session.expiration_mode = expmode
flow_session.save()
return http.HttpResponse("OK")
else:
raise PermissionDenied()
# {{{ view: finish flow
def finish_flow_session_view(pctx, flow_session_id):
Andreas Klöckner
committed
now_datetime = get_now_or_fake_time(pctx.request)
request = pctx.request
flow_session_id = int(flow_session_id)
flow_session = get_and_check_flow_session(
pctx, flow_session_id)
fctx = FlowContext(pctx.repo, pctx.course, flow_id,
participation=pctx.participation,
flow_session=flow_session)
access_rule = get_session_access_rule(
flow_session, pctx.role, fctx.flow_desc, now_datetime,
pctx.remote_address)
answer_visits = assemble_answer_visits(flow_session)
from course.content import markup_to_html
completion_text = markup_to_html(
fctx.course, fctx.repo, pctx.course_commit_sha,
getattr(fctx.flow_desc, "completion_text", ""))
(answered_count, unanswered_count) = count_answered_gradable(
fctx, flow_session, answer_visits)
is_graded_flow = bool(answered_count + unanswered_count)
if flow_permission.view not in access_rule.permissions:
raise PermissionDenied()
def render_finish_response(template, **kwargs):
render_args = {
"flow_desc": fctx.flow_desc,
}
render_args.update(kwargs)
return render_course_page(
pctx, template, render_args,
allow_instant_flow_requests=False)
if request.method == "POST":
if "submit" not in request.POST:
raise SuspiciousOperation(_("odd POST parameters"))
if not flow_session.in_progress:
raise PermissionDenied(
_("Can't end a session that's already ended"))
if flow_permission.end_session not in access_rule.permissions:
raise PermissionDenied(
_("not permitted to end session"))
grading_rule = get_session_grading_rule(
flow_session, pctx.role, fctx.flow_desc, now_datetime)
Andreas Klöckner
committed
grade_info = finish_flow_session(
fctx, flow_session, grading_rule,
Andreas Klöckner
committed
now_datetime=now_datetime)
if is_graded_flow:
return render_finish_response(
"course/flow-completion-grade.html",
completion_text=completion_text,
grade_info=grade_info)
else:
return render_finish_response(
"course/flow-completion.html",
last_page_nr=None,
flow_session=flow_session,
completion_text=completion_text)
(flow_session.in_progress
and flow_permission.end_session not in access_rule.permissions)):
# No ability to end--just show completion page.
return render_finish_response(
"course/flow-completion.html",
flow_session=flow_session,
completion_text=completion_text)
elif not flow_session.in_progress:
# Just reviewing: re-show grades.
grade_info = gather_grade_info(fctx, flow_session, answer_visits)
return render_finish_response(
"course/flow-completion-grade.html",
completion_text=completion_text,
grade_info=grade_info)
else:
# confirm ending flow
return render_finish_response(
"course/flow-confirm-completion.html",
flow_session=flow_session,
answered_count=answered_count,
unanswered_count=unanswered_count,
total_count=answered_count+unanswered_count)
# {{{ view: regrade flow
class RegradeFlowForm(StyledForm):
def __init__(self, flow_ids, *args, **kwargs):
super(RegradeFlowForm, self).__init__(*args, **kwargs)
self.fields["flow_id"] = forms.ChoiceField(
choices=[(fid, fid) for fid in flow_ids],
initial=participation_role.student,
self.fields["access_rules_tag"] = forms.CharField(
help_text=_("If non-empty, limit the regrading to sessions "
"started under this access rules tag."),
self.fields["regraded_session_in_progress"] = forms.ChoiceField(
choices=(
_("Regrade in-progress and not-in-progress sessions")),
_("Regrade in-progress sessions only")),
_("Regrade not-in-progress sessions only")),
),
label=_("Regraded session in progress"))
Submit("regrade", _("Regrade"), css_class="col-lg-offset-2"))
@transaction.atomic
def _regrade_sessions(repo, course, sessions):
count = 0
from course.flow import regrade_session
for session in sessions:
regrade_session(repo, course, session)
count += 1
return count
@course_view
def regrade_not_for_credit_flows_view(pctx):
if pctx.role != participation_role.instructor:
raise PermissionDenied(_("must be instructor to regrade flows"))
from course.content import list_flow_ids
flow_ids = list_flow_ids(pctx.repo, pctx.course_commit_sha)
request = pctx.request
if request.method == "POST":
form = RegradeFlowForm(flow_ids, request.POST, request.FILES)
if form.is_valid():
sessions = (FlowSession.objects
.filter(
course=pctx.course,
flow_id=form.cleaned_data["flow_id"]))
if form.cleaned_data["access_rules_tag"]:
access_rules_tag=form.cleaned_data["access_rules_tag"])
inprog_value = {
"any": None,
"yes": True,
"no": False,
}[form.cleaned_data["regraded_session_in_progress"]]
if inprog_value is not None:
sessions = sessions.filter(
in_progress=inprog_value)
count = _regrade_sessions(pctx.repo, pctx.course, sessions)
messages.add_message(request, messages.SUCCESS,
_("%d sessions regraded.") % count)
else:
form = RegradeFlowForm(flow_ids)
return render_course_page(pctx, "course/generic-course-form.html", {
"form": form,
"form_text": string_concat(
"<p>",
_("This regrading process is only intended for flows that do"
"not show up in the grade book. If you would like to regrade"
"for-credit flows, use the corresponding functionality in "
"form_description": _("Regrade not-for-credit Flow Sessions"),