Newer
Older
# {{{ 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']
answer_data = page_visit.answer = fpctx.page.answer_data(
fpctx.page_context, fpctx.page_data.data,
form, request.FILES)
page_visit.is_graded_answer = pressed_button == "submit"
answer_was_graded = page_visit.is_graded_answer
may_change_answer = (
not answer_was_graded
or flow_permission.change_answer
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 = pctx.course_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(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(permissions)):
return redirect("course.flow.finish_flow_session_view",
pctx.course.identifier, flow_identifier)
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_graded_answer
else:
answer_was_graded = False
may_change_answer = (
(not answer_was_graded
or (flow_permission.change_answer in permissions))
and flow_session.in_progress)
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:
if most_recent_grade.feedback is not None:
from course.page import AnswerFeedback
feedback = AnswerFeedback.from_json(
most_recent_grade.feedback)
else:
feedback = None
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:
flow_permission.see_correctness in permissions
or (
(flow_permission.see_correctness_after_completion
and not flow_session.in_progress))
show_answer = (
flow_permission.see_answer in permissions
or (
(flow_permission.see_answer_after_completion
in permissions)
and not flow_session.in_progress))
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
or (
(flow_permission.see_answer_after_completion
in permissions)
and not flow_session.in_progress))
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, current_access_rule.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():
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)
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
@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)
current_access_rule = fctx.get_current_access_rule(
flow_session, pctx.role, pctx.participation,
get_now_or_fake_time(pctx.request))
if is_expiration_mode_allowed(expmode, current_access_rule.permissions):
flow_session.expiration_mode = expmode
flow_session.save()
return http.HttpResponse("OK")
else:
raise PermissionDenied()
# {{{ view: finish flow
@course_view
def finish_flow_session_view(pctx, flow_identifier):
Andreas Klöckner
committed
now_datetime = get_now_or_fake_time(pctx.request)
request = pctx.request
flow_session = find_current_flow_session(
request, pctx.course, flow_identifier)
if flow_session is None:
messages.add_message(request, messages.WARNING,
"No session record found for this flow. "
"Redirected to flow start page.")
return redirect("course.flow.start_flow",
pctx.course.identifier,
fctx = FlowContext(pctx.repo, pctx.course, flow_identifier,
participation=pctx.participation,
flow_session=flow_session)
current_access_rule = fctx.get_current_access_rule(
flow_session, pctx.role, pctx.participation,
get_now_or_fake_time(request))
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(
fctx, flow_session, answer_visits)
is_graded_flow = bool(answered_count + unanswered_count)
if flow_permission.view not in current_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")
# Actually end the flow session
get_flow_session_id_map(request)[flow_identifier] = None
Andreas Klöckner
committed
grade_info = finish_flow_session(
fctx, flow_session, current_access_rule,
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,
completion_text=completion_text)
if not is_graded_flow:
# Not serious--no questions in flow.
return render_finish_response(
"course/flow-completion.html",
completion_text=completion_text)
elif not flow_session.in_progress:
# Just reviewing: re-show grades.
grade_info = gather_grade_info(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",
answered_count=answered_count,
unanswered_count=unanswered_count,
total_count=answered_count+unanswered_count)
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
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
# {{{ 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_id"] = forms.CharField(
required=False,
help_text="If non-empty, limit the regrading to sessions started "
"under this access rules ID.")
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"],
for_credit=False))
if form.cleaned_data["access_rules_id"]:
sessions = sessions.filter(
access_rules_id=form.cleaned_data["access_rules_id"])
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 only considers not-for-credit flow "
"sessions. 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",
})
# }}}