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} )
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"), })
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"), })
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, )
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", })