Example #1
0
        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)
Example #2
0
        def staff_add_extension(netid, cid, aid):
            assignment = db.get_assignment(cid, aid)
            if not assignment:
                return util.error(
                    "Invalid course or assignment. Please try again.")

            if util.check_missing_fields(request.form, "netids", "max_runs",
                                         "start", "end"):
                return util.error("Missing fields. Please try again.")

            student_netids = request.form["netids"].replace(
                " ", "").lower().split(",")
            for student_netid in student_netids:
                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:
                max_runs = int(request.form["max_runs"])
                if max_runs < 1:
                    return util.error("Max Runs must be a positive integer.")
            except ValueError:
                return util.error("Max Runs must be a positive integer.")

            start = util.parse_form_datetime(request.form["start"]).timestamp()
            end = util.parse_form_datetime(request.form["end"]).timestamp()
            if start >= end:
                return util.error("Start must be before End.")

            for student_netid in student_netids:
                db.add_extension(cid, aid, student_netid, max_runs, start, end)
            return util.success("")
Example #3
0
        def add_assignment(netid, cid):
            missing = util.check_missing_fields(
                request.form, *[
                    "aid", "max_runs", "quota", "start", "end", "config",
                    "visibility"
                ])
            if missing:
                return util.error(f"Missing fields ({', '.join(missing)}).")

            aid = request.form["aid"]
            if not util.valid_id(aid):
                return util.error(
                    "Invalid Assignment ID. Allowed characters: a-z A-Z _ - .")

            new_assignment = db.get_assignment(cid, aid)
            if new_assignment:
                return util.error("Assignment ID already exists.")

            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 = json.loads(request.form["config"])
                msg = bw_api.set_assignment_config(cid, aid, config)

                if msg:
                    return util.error(
                        f"Failed to add assignment to Broadway: {msg}")
            except json.decoder.JSONDecodeError:
                return util.error("Failed to decode config JSON")

            visibility = request.form["visibility"]

            db.add_assignment(cid, aid, max_runs, quota, start, end,
                              visibility)
            return util.success("")
Example #4
0
        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("")
Example #5
0
def get_available_runs(cid, aid, netid, now=None):
    if now is None:
        now = util.now_timestamp()

    assignment = db.get_assignment(cid, aid)

    if not in_grading_period(assignment, now):
        return 0

    runs = db.get_assignment_runs_for_student(cid, aid, netid)

    if assignment["quota"] == db.Quota.TOTAL:
        return max(assignment["max_runs"] - len(runs), 0)
    elif assignment["quota"] == db.Quota.DAILY:
        today_runs = list(filter(lambda r: is_run_today(r, now), runs))
        return max(assignment["max_runs"] - len(today_runs), 0)
Example #6
0
        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)
Example #7
0
        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("")