def student_assignment_show_deadline(ctx, course, assignment_id, utc): assignment = course.get_assignment(assignment_id) if assignment is None: print("Assignment %s does not exist" % assignment_id) ctx.exit(CHISUBMIT_FAIL) now_utc = get_datetime_now_utc() now_local = convert_datetime_to_local(now_utc) deadline_utc = assignment.deadline deadline_local = convert_datetime_to_local(deadline_utc) print(assignment.name) print() if utc: print(" Now (Local): %s" % now_local.isoformat(" ")) print(" Deadline (Local): %s" % deadline_local.isoformat(" ")) print() print(" Now (UTC): %s" % now_utc.isoformat(" ")) print(" Deadline (UTC): %s" % deadline_utc.isoformat(" ")) else: print(" Now: %s" % now_local.isoformat(" ")) print(" Deadline: %s" % deadline_local.isoformat(" ")) print() extensions = compute_extensions_needed(now_utc, deadline_utc) if extensions == 0: diff = deadline_utc - now_utc else: diff = now_utc - deadline_utc days = diff.days hours = diff.seconds // 3600 minutes = (diff.seconds // 60) % 60 seconds = diff.seconds % 60 if extensions == 0: print("The deadline has not yet passed") print("You have %i days, %i hours, %i minutes, %i seconds left" % (days, hours, minutes, seconds)) else: print( "The deadline passed %i days, %i hours, %i minutes, %i seconds ago" % (days, hours, minutes, seconds)) print( "If you submit your assignment now, you will need to use %i extensions" % extensions) return CHISUBMIT_SUCCESS
def student_assignment_show_deadline(ctx, course, assignment_id, utc): assignment = course.get_assignment(assignment_id) if assignment is None: print("Assignment %s does not exist" % assignment_id) ctx.exit(CHISUBMIT_FAIL) now_utc = get_datetime_now_utc() now_local = convert_datetime_to_local(now_utc) deadline_utc = assignment.deadline deadline_local = convert_datetime_to_local(deadline_utc) print(assignment.name) print() if utc: print(" Now (Local): %s" % now_local.isoformat(" ")) print(" Deadline (Local): %s" % deadline_local.isoformat(" ")) print() print(" Now (UTC): %s" % now_utc.isoformat(" ")) print(" Deadline (UTC): %s" % deadline_utc.isoformat(" ")) else: print(" Now: %s" % now_local.isoformat(" ")) print(" Deadline: %s" % deadline_local.isoformat(" ")) print() extensions = compute_extensions_needed(now_utc, deadline_utc) if extensions == 0: diff = deadline_utc - now_utc else: diff = now_utc - deadline_utc days = diff.days hours = diff.seconds // 3600 minutes = (diff.seconds//60)%60 seconds = diff.seconds%60 if extensions == 0: print("The deadline has not yet passed") print("You have %i days, %i hours, %i minutes, %i seconds left" % (days, hours, minutes, seconds)) else: print("The deadline passed %i days, %i hours, %i minutes, %i seconds ago" % (days, hours, minutes, seconds)) print("If you submit your assignment now, you will need to use %i extensions" % extensions) return CHISUBMIT_SUCCESS
def assignment_submit(course_id, assignment_id): now = get_datetime_now_utc() course = Course.query.filter_by(id=course_id).first() if course is None: abort(404) check_course_access_or_abort(g.user, course, 404, roles=["student"]) assignment = Assignment.query.filter_by(id=assignment_id, course_id=course_id).first() # TODO 12DEC14: check permissions *before* 404 if assignment is None: abort(404) if not g.user.is_student_in(course): error_msg = "You are not a student in course '%s'" % (course_id) return jsonify(errors={"register": error_msg}), 400 if request.method == 'POST': input_data = request.get_json(force=True) if not isinstance(input_data, dict): return jsonify(error='Request data must be a JSON Object'), 400 form = SubmitAssignmentInput.from_json(input_data) if not form.validate(): return jsonify(errors=form.errors), 400 team_id = form.team_id.data commit_sha = form.commit_sha.data extensions_requested = form.extensions.data dry_run = form.dry_run.data team = Team.query.filter_by(id=team_id).first() if team is None: abort(404) check_team_access_or_abort(g.user, team, 404) team_assignment = AssignmentsTeams.from_id(course.id,team.id,assignment.id) if team_assignment is None: msg = "Team '%s' is not registered for assignment '%s'" % (team.id, assignment.id) return jsonify(errors={"team":msg}), 400 if team_assignment.is_ready_for_grading(): msg = "You cannot re-submit assignment %s." % (assignment.id) msg = " You made a submission before the deadline, and the deadline has passed." return jsonify(errors={"submit":msg}), 400 response = {} response["dry_run"] = dry_run response["prior_submission"] = {} response["prior_submission"]["submitted_at"] = team_assignment.submitted_at response["prior_submission"]["commit_sha"] = team_assignment.commit_sha response["prior_submission"]["extensions_used"] = team_assignment.extensions_used response["submission"] = {} response["submission"]["course_id"] = course.id response["submission"]["assignment_id"] = assignment.id response["submission"]["submitted_at"] = now response["submission"]["deadline"] = assignment.deadline extensions_needed = compute_extensions_needed(submission_time = now, deadline = assignment.deadline) extension_policy = course.options.get("extension-policy", None) extensions_available = team.get_extensions_available(extension_policy) if extensions_available < 0: error_msg = "The number of available extensions is negative" return jsonify(errors={"fatal": error_msg}), 500 response["submission"]["extensions_requested"] = extensions_requested response["submission"]["extensions_needed"] = extensions_needed response["team"] = {} response["team"]["id"] = team.id response["team"]["extensions_available_before"] = extensions_available if extensions_available + team_assignment.extensions_used >= extensions_needed and extensions_requested == extensions_needed: response["success"] = True # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += team_assignment.extensions_used extensions_available -= extensions_needed if not dry_run: team_assignment.extensions_used = extensions_needed team_assignment.commit_sha = commit_sha team_assignment.submitted_at = now db.session.add(team_assignment) db.session.commit() else: response["success"] = False response["team"]["extensions_available"] = extensions_available return jsonify(response)
def assignment_submit(course_id, assignment_id): now = get_datetime_now_utc() course = Course.query.filter_by(id=course_id).first() if course is None: abort(404) check_course_access_or_abort(g.user, course, 404, roles=["student"]) assignment = Assignment.query.filter_by(id=assignment_id, course_id=course_id).first() # TODO 12DEC14: check permissions *before* 404 if assignment is None: abort(404) if not g.user.is_student_in(course): error_msg = "You are not a student in course '%s'" % (course_id) return jsonify(errors={"register": error_msg}), 400 if request.method == 'POST': input_data = request.get_json(force=True) if not isinstance(input_data, dict): return jsonify(error='Request data must be a JSON Object'), 400 form = SubmitAssignmentInput.from_json(input_data) if not form.validate(): return jsonify(errors=form.errors), 400 team_id = form.team_id.data commit_sha = form.commit_sha.data extensions_requested = form.extensions.data dry_run = form.dry_run.data team = Team.query.filter_by(id=team_id).first() if team is None: abort(404) check_team_access_or_abort(g.user, team, 404) team_assignment = AssignmentsTeams.from_id(course.id, team.id, assignment.id) if team_assignment is None: msg = "Team '%s' is not registered for assignment '%s'" % ( team.id, assignment.id) return jsonify(errors={"team": msg}), 400 if team_assignment.is_ready_for_grading(): msg = "You cannot re-submit assignment %s." % (assignment.id) msg = " You made a submission before the deadline, and the deadline has passed." return jsonify(errors={"submit": msg}), 400 response = {} response["dry_run"] = dry_run response["prior_submission"] = {} response["prior_submission"][ "submitted_at"] = team_assignment.submitted_at response["prior_submission"]["commit_sha"] = team_assignment.commit_sha response["prior_submission"][ "extensions_used"] = team_assignment.extensions_used response["submission"] = {} response["submission"]["course_id"] = course.id response["submission"]["assignment_id"] = assignment.id response["submission"]["submitted_at"] = now response["submission"]["deadline"] = assignment.deadline extensions_needed = compute_extensions_needed( submission_time=now, deadline=assignment.deadline) extension_policy = course.options.get("extension-policy", None) extensions_available = team.get_extensions_available(extension_policy) if extensions_available < 0: error_msg = "The number of available extensions is negative" return jsonify(errors={"fatal": error_msg}), 500 response["submission"]["extensions_requested"] = extensions_requested response["submission"]["extensions_needed"] = extensions_needed response["team"] = {} response["team"]["id"] = team.id response["team"]["extensions_available_before"] = extensions_available if extensions_available + team_assignment.extensions_used >= extensions_needed and extensions_requested == extensions_needed: response["success"] = True # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += team_assignment.extensions_used extensions_available -= extensions_needed if not dry_run: team_assignment.extensions_used = extensions_needed team_assignment.commit_sha = commit_sha team_assignment.submitted_at = now db.session.add(team_assignment) db.session.commit() else: response["success"] = False response["team"]["extensions_available"] = extensions_available return jsonify(response)
def create(cls, registration, commit_sha, submitted_at, extensions_override): deadline = registration.assignment.deadline grace_period = registration.assignment.grace_period effective_deadline = deadline + grace_period extensions_needed = compute_extensions_needed(submission_time = submitted_at, deadline = effective_deadline) extensions_needed_without_grace_period = compute_extensions_needed(submission_time = submitted_at, deadline = deadline) if extensions_override is None and extensions_needed_without_grace_period == extensions_needed + 1: in_grace_period = True else: in_grace_period = False extensions_available = registration.team.get_extensions_available() if extensions_available < 0: msg = "The number of available extensions is negative" return False, Response({"fatal": [msg]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR), None if registration.final_submission is not None: extensions_used_in_existing_submission = registration.final_submission.extensions_used else: extensions_used_in_existing_submission = 0 error_data = {"extensions_available": extensions_available, "extensions_needed": extensions_needed, "submitted_at": submitted_at.isoformat(sep=" "), "deadline": registration.assignment.deadline.isoformat(sep=" ")} if extensions_override is None and extensions_available + extensions_used_in_existing_submission < extensions_needed: msg = "You do not have enough extensions to make this submission." response_data = {"errors": [msg]} response_data.update(error_data) response = Response(response_data, status=status.HTTP_400_BAD_REQUEST) raise SubmissionValidationException(response) if extensions_override is not None and extensions_available + extensions_used_in_existing_submission - extensions_override < 0: msg = "The extensions override you have specified would leave the team with a negative number of extensions." error_data["extensions_override"] = extensions_override response_data = {"errors": [msg]} response_data.update(error_data) response = Response(response_data, status=status.HTTP_400_BAD_REQUEST) raise SubmissionValidationException(response) else: extensions = {} extensions["extensions_available_before"] = extensions_available # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += extensions_used_in_existing_submission if extensions_override is not None: extensions["extensions_override"] = extensions_override extensions_used = extensions_override else: extensions_used = extensions_needed extensions_available -= extensions_used extensions["extensions_available_after"] = extensions_available extensions["extensions_needed"] = extensions_needed submission = cls(registration = registration, extensions_used = extensions_used, commit_sha = commit_sha, submitted_at = submitted_at, in_grace_period = in_grace_period) return submission, extensions
def create(cls, registration, commit_sha, submitted_at, submitted_by, extensions_override): deadline = registration.assignment.deadline grace_period = registration.assignment.grace_period effective_deadline = deadline + grace_period extensions_needed = compute_extensions_needed(submission_time = submitted_at, deadline = effective_deadline) extensions_needed_without_grace_period = compute_extensions_needed(submission_time = submitted_at, deadline = deadline) if extensions_override is None and extensions_needed_without_grace_period == extensions_needed + 1: in_grace_period = True else: in_grace_period = False extensions_available = registration.team.get_extensions_available() if extensions_available < 0: msg = "The number of available extensions is negative" return False, Response({"fatal": [msg]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR), None if registration.final_submission is not None: extensions_used_in_existing_submission = registration.final_submission.extensions_used else: extensions_used_in_existing_submission = 0 error_data = {"extensions_available": extensions_available, "extensions_needed": extensions_needed, "submitted_at": submitted_at.isoformat(sep=" "), "deadline": registration.assignment.deadline.isoformat(sep=" ")} if extensions_override is None and extensions_available + extensions_used_in_existing_submission < extensions_needed: msg = "You do not have enough extensions to make this submission." response_data = {"errors": [msg]} response_data.update(error_data) response = Response(response_data, status=status.HTTP_400_BAD_REQUEST) raise SubmissionValidationException(response) if extensions_override is not None and extensions_available + extensions_used_in_existing_submission - extensions_override < 0: msg = "The extensions override you have specified would leave the team with a negative number of extensions." error_data["extensions_override"] = extensions_override response_data = {"errors": [msg]} response_data.update(error_data) response = Response(response_data, status=status.HTTP_400_BAD_REQUEST) raise SubmissionValidationException(response) else: extensions = {} extensions["extensions_available_before"] = extensions_available # If the team has already used extensions for a previous submission, # they don't count towards the number of extensions needed # They are 'credited' to the available extensions extensions_available += extensions_used_in_existing_submission if extensions_override is not None: extensions["extensions_override"] = extensions_override extensions_used = extensions_override else: extensions_used = extensions_needed extensions_available -= extensions_used extensions["extensions_available_after"] = extensions_available extensions["extensions_needed"] = extensions_needed submission = cls(registration = registration, extensions_used = extensions_used, commit_sha = commit_sha, submitted_at = submitted_at, submitted_by = submitted_by, in_grace_period = in_grace_period) return submission, extensions