def student_get_course(netid, cid): if not verify_student_or_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) course = db.get_course(cid) if verify_staff(netid, cid): assignments = db.get_assignments_for_course(cid) else: assignments = db.get_assignments_for_course(cid, visible_only=True) now = util.now_timestamp() for assignment in assignments: num_available_runs = get_available_runs( cid, assignment["assignment_id"], netid, now) active_extensions, num_extension_runs = get_active_extensions( cid, assignment["assignment_id"], netid, now) total_available_runs = num_extension_runs + num_available_runs if verify_staff(netid, cid): total_available_runs = max(total_available_runs, 1) assignment.update( {"total_available_runs": total_available_runs}) return render_template("student/course.html", netid=netid, course=course, assignments=assignments, now=now, tzname=str(TZ))
def student_get_assignment(netid, cid, aid): if not verify_student_or_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) course = db.get_course(cid) assignment = db.get_assignment(cid, aid) runs = db.get_assignment_runs_for_student(cid, aid, netid) now = util.now_timestamp() num_available_runs = get_available_runs(cid, aid, netid, now) active_extensions, num_extension_runs = get_active_extensions( cid, aid, netid, now) user = db.get_user(netid) commit = get_latest_commit(netid, user["access_token"], course["github_org"]) if verify_staff(netid, cid): num_available_runs = max(num_available_runs, 1) return render_template("student/assignment.html", netid=netid, course=course, assignment=assignment, commit=commit, runs=runs, num_available_runs=num_available_runs, num_extension_runs=num_extension_runs, tzname=str(TZ), broadway_api_url=BROADWAY_API_URL)
def verify_student(netid, cid): """ Check whether the given NetID is a student in the given course. :param netid: a user's NetID. :param cid: a course ID. :return: a boolean value. """ return netid in db.get_course(cid)["student_ids"]
def verify_admin(netid, cid): """ Check whether the given NetID is a course admin in the given course. :param netid: a user's NetID. :param cid: a course ID. :return: a boolean value. """ staff = db.get_course(cid)["staff"] if netid not in staff: return False else: return staff[netid]["is_admin"]
def get_course_staff_roster(netid, cid): course = db.get_course(cid) staff = course["staff"] # get all admin_ids by filtering out all non-admins admin = dict( filter(lambda x: x[1].get("is_admin") == True, staff.items())) admin = list(admin.keys()) # get the entire staff total_staff = list(staff.keys()) return jsonify(admin_ids=admin, staff_ids=total_staff, user=netid)
def edit_assignment(netid, cid, aid): course = db.get_course(cid) assignment = db.get_assignment(cid, aid) if course is None or assignment is None: return abort(HTTPStatus.NOT_FOUND) missing = util.check_missing_fields( request.form, *["max_runs", "quota", "start", "end", "visibility"]) if missing: return util.error(f"Missing fields ({', '.join(missing)}).") try: max_runs = int(request.form["max_runs"]) if max_runs < MIN_PREDEADLINE_RUNS: return util.error( f"Max Runs must be at least {MIN_PREDEADLINE_RUNS}.") except ValueError: return util.error("Max Runs must be a positive integer.") quota = request.form["quota"] if not db.Quota.is_valid(quota): return util.error("Quota Type is invalid.") start = util.parse_form_datetime(request.form["start"]).timestamp() end = util.parse_form_datetime(request.form["end"]).timestamp() if start is None or end is None: return util.error("Missing or invalid Start or End.") if start >= end: return util.error("Start must be before End.") try: config_str = request.form.get("config") if config_str is not None: # skip update otherwise config = json.loads(request.form["config"]) msg = bw_api.set_assignment_config(cid, aid, config) if msg: return util.error( f"Failed to update assignment config to Broadway: {msg}" ) except json.decoder.JSONDecodeError: return util.error("Failed to decode config JSON") visibility = request.form["visibility"] if not db.update_assignment(cid, aid, max_runs, quota, start, end, visibility): return util.error("Save failed or no changes were made.") return util.success("")
def staff_get_course(netid, cid): if not verify_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) course = db.get_course(cid) assignments = db.get_assignments_for_course(cid) is_admin = verify_admin(netid, cid) now = util.now_timestamp() return render_template("staff/course.html", netid=netid, course=course, assignments=assignments, tzname=str(TZ), is_admin=is_admin, now=now, visibility=db.Visibility, error=None)
def staff_get_assignment(netid, cid, aid): if not verify_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) course = db.get_course(cid) assignment = db.get_assignment(cid, aid) student_runs = list(db.get_assignment_runs(cid, aid)) scheduled_runs = list(db.get_scheduled_runs(cid, aid)) is_admin = verify_admin(netid, cid) return render_template( "staff/assignment.html", netid=netid, course=course, assignment=assignment, student_runs=student_runs, scheduled_runs=scheduled_runs, sched_run_status=sched_api.ScheduledRunStatus, tzname=str(TZ), is_admin=is_admin, visibility=db.Visibility, broadway_api_url=BROADWAY_API_URL)
def trigger_scheduled_run(cid, aid, scheduled_run_id): sched_run = db.get_scheduled_run_by_scheduler_id( cid, aid, scheduled_run_id) if sched_run is None: logging.warning( "Received trigger scheduled run request for scheduled_run_id '%s' but cannot find corresponding run.", scheduled_run_id) return util.error("") if sched_run["status"] != ScheduledRunStatus.SCHEDULED: logging.warning( "Received trigger scheduled run for _id '%s' but this run has status '%s', which is not 'scheduled'.", str(sched_run["_id"]), sched_run["status"]) return util.error("") # If roster is not provided, use course roster if sched_run["roster"] is None: course = db.get_course(cid) if course is None: return util.error("") netids = course["student_ids"] # If a roster is provided, use it else: netids = sched_run["roster"] # Start broadway grading run bw_run_id = bw_api.start_grading_run(cid, f"{aid}_{sched_run['_id']}", netids, sched_run["due_time"]) if bw_run_id is None: logging.warning("Failed to trigger run with broadway") db.update_scheduled_run_status(sched_run["_id"], ScheduledRunStatus.FAILED) return util.error("") else: db.update_scheduled_run_status(sched_run["_id"], ScheduledRunStatus.RAN) db.update_scheduled_run_bw_run_id(sched_run["_id"], bw_run_id) return util.success("")
def build_header(cid): token = db.get_course(cid)["token"] return {"Authorization": f"Bearer {token}"}
def get_course_student_roster(netid, cid): course = db.get_course(cid) return jsonify(course['student_ids'])
def add_or_edit_scheduled_run(cid, aid, run_id, form, scheduled_run_id): # course and assignment name validation course = db.get_course(cid) assignment = db.get_assignment(cid, aid) if course is None or assignment is None: return abort(HTTPStatus.NOT_FOUND) # form validation missing = util.check_missing_fields(request.form, "run_time", "due_time", "name", "config") if missing: return util.error(f"Missing fields ({', '.join(missing)}).") run_time = util.parse_form_datetime( request.form["run_time"]).timestamp() if run_time is None: return util.error("Missing or invalid run time.") if run_time <= util.now_timestamp(): return util.error("Run time must be in the future.") due_time = util.parse_form_datetime( request.form["due_time"]).timestamp() if due_time is None: return util.error("Missing or invalid due time.") if "roster" not in request.form or not request.form["roster"]: roster = None else: roster = request.form["roster"].replace(" ", "").lower().split(",") for student_netid in roster: if not util.valid_id(student_netid) or not verify_student( student_netid, cid): return util.error( f"Invalid or non-existent student NetID: {student_netid}" ) try: config = json.loads(request.form["config"]) msg = bw_api.set_assignment_config(cid, f"{aid}_{run_id}", config) if msg: return util.error( f"Failed to upload config to Broadway: {msg}") except json.decoder.JSONDecodeError: return util.error("Failed to decode config JSON") # Schedule a new run with scheduler if scheduled_run_id is None: scheduled_run_id = sched_api.schedule_run(run_time, cid, aid) if scheduled_run_id is None: return util.error("Failed to schedule run with scheduler") # Or if the run was already scheduled, update the time else: if not sched_api.update_scheduled_run(scheduled_run_id, run_time): return util.error( "Failed to update scheduled run time with scheduler") assert scheduled_run_id is not None if not db.add_or_update_scheduled_run( run_id, cid, aid, run_time, due_time, roster, request.form["name"], scheduled_run_id): return util.error( "Failed to save the changes, please try again.") return util.success("")
def get_course_roster_page(netid, cid): course = db.get_course(cid) return render_template("staff/roster.html", netid=netid, course=course)