Newer
Older
answer_was_graded = page_visit.is_submitted_answer
may_change_answer = (
not answer_was_graded
or flow_permission.change_answer
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()
grade.save()
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("course.flow.view_flow_page",
pctx.course.identifier,
fpctx.ordinal + 1)
elif (pressed_button == "save_and_finish"
and not will_receive_feedback(permissions)):
return redirect("course.flow.finish_flow_session_view",
pctx.course.identifier, flow_session_id)
form = fpctx.page.make_form(
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_submitted_answer
else:
answer_was_graded = False
may_change_answer = (
(not answer_was_graded
or (flow_permission.change_answer in permissions))
Andreas Klöckner
committed
and flow_session.in_progress
and (flow_permission.submit_answer in permissions))
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(
answer_data, not may_change_answer)
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,
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 permissions
show_answer = flow_permission.see_answer in permissions
if show_correctness or show_answer:
shown_feedback = feedback
elif fpctx.page.expects_answer() and not answer_was_graded:
# Don't show answer yet
pass
else:
show_answer = flow_permission.see_answer in permissions
title = fpctx.page.title(page_context, page_data.data)
body = fpctx.page.body(page_context, page_data.data)
if show_answer:
correct_answer = fpctx.page.correct_answer(
page_context, page_data.data,
answer_data, grade_data)
else:
correct_answer = None
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))
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,
"page_numbers": zip(
range(flow_session.page_count),
range(1, flow_session.page_count+1)),
"feedback": shown_feedback,
"correct_answer": correct_answer,
"may_change_graded_answer": (
(flow_permission.change_answer
and flow_session.in_progress),
"will_receive_feedback": will_receive_feedback(permissions),
"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)
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
@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))
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)
flow_identifier = flow_session.flow_id
fctx = FlowContext(pctx.repo, pctx.course, flow_identifier,
participation=pctx.participation,
flow_session=flow_session)
access_rule = get_session_access_rule(
flow_session, pctx.role, fctx.flow_desc, now_datetime)
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,
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_identifier": fctx.flow_identifier,
"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_flow not in access_rule.permissions:
raise PermissionDenied("not permitted to end flow")
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)
if (not is_graded_flow
or
flow_permission.end_flow 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,
required=True)
self.fields["access_rules_tag"] = forms.CharField(
required=False,
help_text="If non-empty, limit the regrading to sessions started "
"under this access rules tag.")
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
self.fields["regraded_session_in_progress"] = forms.ChoiceField(
choices=(
("any", "Regrade in-progress and not-in-progress sessions"),
("yes", "Regrade in-progress sessions only"),
("no", "Regrade not-in-progress sessions only"),
))
self.helper.add_input(
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"])
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
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":
"<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 the grade book.</p>",
"form_description": "Regrade not-for-credit Flow Sessions",
})