def t_NUM(t): r'-?\d+' num = int(t.value) if not is_in_range(num): error(t.lexer.lineno, create_not_in_range_message(num)) t.value = num return t
def validate_loop_iterator_modification(scope, variable_node): variable_name = variable_node.variable if variable_name in scope: dec = scope[variable_name] if dec.local is True: error(variable_node.line, loop_iterator_modifiaction(variable_name))
def promote_course_staff(netid, cid): staff_id = request.form.get('netid') if not verify_staff(staff_id, cid): return util.error(f"'{staff_id}' is not a staff") result = db.add_admin_to_course(cid, staff_id) if none_modified(result): return util.error(f"'{staff_id}' is already an admin") return util.success(f"Successfully made '{staff_id}' admin")
def staff_delete_scheduled_run(netid, cid, aid, run_id): sched_run = db.get_scheduled_run(cid, aid, run_id) if sched_run is None: return util.error("Cannot find scheduled run") sched_api.delete_scheduled_run(sched_run["scheduled_run_id"]) if not db.delete_scheduled_run(cid, aid, run_id): return util.error( "Failed to delete scheduled run. Please try again") return util.success("")
def validate_array_accessor_in_range(scope, variable_node): if isinstance(variable_node, IdentifierArrayNumber): accessor_index = variable_node.accessor declared_variable = scope[variable_node.variable] if not declared_variable.start_index <= accessor_index <= declared_variable.end_index: error( variable_node.line, accessor_not_in_range(accessor_index, declared_variable.start_index, declared_variable.end_index, declared_variable.id))
def add_course_staff(netid, cid): new_staff_id = request.form.get('netid').lower() if new_staff_id is None: return util.error("Cannot find netid field") if not util.is_valid_netid(new_staff_id): return util.error(f"Poorly formatted NetID: '{new_staff_id}'") result = db.add_staff_to_course(cid, str(new_staff_id)) if none_modified(result): return util.error( f"'{new_staff_id}' is already a course staff") return util.success(f"Successfully added {new_staff_id}")
def staff_edit_scheduled_run(netid, cid, aid, run_id): sched_run = db.get_scheduled_run(cid, aid, run_id) if sched_run is None: return util.error( "Could not find this scheduled run. Please refresh and try again." ) if sched_run["status"] != sched_api.ScheduledRunStatus.SCHEDULED: return util.error("Cannot edit past runs") scheduled_run_id = sched_run["scheduled_run_id"] return add_or_edit_scheduled_run(cid, aid, run_id, request.form, scheduled_run_id)
def staff_delete_extension(netid, cid, aid): extension_id = request.form["_id"] delete_result = db.delete_extension(extension_id) if delete_result is None: return util.error( "Invalid extension, please refresh the page.") if delete_result.deleted_count != 1: return util.error("Failed to delete extension.") return util.success("")
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("")
def upload_roster_file(netid, cid): file_content = request.form.get('content') netids = file_content.strip().lower().split('\n') for i, student_id in enumerate(netids): if not util.is_valid_netid(student_id): return util.error( f"Poorly formatted NetID on line {i + 1}: '{student_id}'" ) result = db.overwrite_student_roster(cid, netids) if none_modified(result): return util.error( "The new roster is the same as the current one.") return util.success("Successfully updated roster.")
def validate_initialized(scope, variable_node): variable_name = variable_node.variable dec = scope[variable_name] if isinstance(variable_node, IdentifierVariable): if not dec.initialized: error(variable_node.line, variable_not_initialized(variable_name)) if isinstance(variable_node, IdentifierArrayNumber): shifted_index = abs(scope[variable_name].start_index - variable_node.accessor) if not dec.initialized: error( variable_node, variable_not_initialized( f'{variable_name}({variable_node.accessor})')) if isinstance(variable_node, IdentifierArrayVariable): pass # too complicated for this compiler
def validate_iterator_not_in_loop_range(for_loop, local_iterator): identifiers = extract_identifiers_from_forloop(for_loop.value_from, for_loop.value_to) [ error(local_iterator.line, using_local_in_loop_range(i.variable)) for i in identifiers if i.variable is local_iterator.variable ]
def staff_get_run_log(netid, cid, aid, run_id): if not verify_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) log = bw_api.get_grading_run_log(cid, run_id) if log: return util.success(jsonify(log), HTTPStatus.OK) return util.error("")
def staff_get_workers(netid, cid): if not verify_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) workers = bw_api.get_workers(cid) if workers is not None: return util.success(jsonify(workers), HTTPStatus.OK) return util.error("")
def demote_course_admin(netid, cid): staff_id = request.form.get('netid') if not verify_staff(staff_id, cid) or not verify_admin( staff_id, cid): return util.error(f"'{staff_id}' is not a admin") db.remove_admin_from_course(cid, staff_id) return util.success( f"Successfully removed '{staff_id}' from admin")
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 admin_update_roster(netid, cid): netids = request.form["roster"].strip().lower().split("\n") for i, student_id in enumerate(netids): if not util.is_valid_netid(student_id): return util.error( f"Poorly formatted NetID on line {i + 1}: '{student_id}'" ) db.overwrite_student_roster(cid, netids) return util.success("Successfully updated roster.", HTTPStatus.OK)
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("")
def student_grade_assignment(netid, cid, aid): if not verify_student_or_staff(netid, cid): return abort(HTTPStatus.FORBIDDEN) if not verify_csrf_token(request.form.get("csrf_token")): return abort(HTTPStatus.BAD_REQUEST) now = util.now_timestamp() ext_to_use = None current_csrf_token = request.form.get("csrf_token") if not verify_staff(netid, cid): # not a staff member; perform quota checks num_available_runs = get_available_runs(cid, aid, netid, now) active_extensions, num_extension_runs = get_active_extensions( cid, aid, netid, now) if num_available_runs + num_extension_runs <= 0: restore_csrf_token(current_csrf_token) return util.error("No grading runs available.") if num_available_runs <= 0: # find the extension that is closest to expiration ext_to_use = min(active_extensions, key=lambda ext: ext["end"]) now_rounded = util.timestamp_round_up_minute(now) run_id = bw_api.start_grading_run(cid, aid, [netid], now_rounded) if run_id is None: restore_csrf_token(current_csrf_token) return util.error( "Failed to start grading run. Please try again.") db.add_grading_run(cid, aid, netid, now, run_id, extension_used=ext_to_use) return util.success("")
def login_ghe_callback(): code = request.args.get("code") if code is None: return util.error("Invalid request; missing code argument.") access_token = ghe_api.get_access_token(code) if access_token is None: return redirect(url_for(".login_page") + '?error=1') netid = ghe_api.get_login(access_token) if netid is None: return redirect(url_for(".login_page") + '?error=1') db.set_user_access_token(netid, access_token) auth.set_uid(netid) return redirect(url_for(".root"))
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 detect_wrong_array_range(node): if node.start_index > node.end_index: error(node.line, "Invalid range of array with id {}.".format(node.id))
def detect_redeclaration(node, list_of_declarations): list_of_ids = map(lambda n: n.id, list_of_declarations) if node.id in list_of_ids: error(node.line, "Second declaration of variable {}".format(node.id))
def staff_get_scheduled_run(netid, cid, aid, run_id): sched_run = db.get_scheduled_run(cid, aid, run_id) if sched_run is None: return util.error("Cannot find scheduled run") del sched_run["_id"] return util.success(json.dumps(sched_run), 200)
def t_error(t): error(t.lexer.lineno, 'Unknown symbol: {}'.format(t.value[0])) pass
def remove_course_staff(netid, cid): staff_id = request.form.get('netid') result = db.remove_staff_from_course(cid, staff_id) if none_modified(result): return util.error(f"'{staff_id}' is not a staff") return util.success(f"Successfully removed '{staff_id}'")
def validate_variable_not_declared(scope, variable_node): variable_name = variable_node.variable if variable_name not in scope: error(variable_node.line, ndeclared_msg(variable_name))
def p_error(p): error(p.lineno, "Unknown input {}".format(p.value))
def validate_iterator_not_in_scope(local_iterator, scope): variable_name = local_iterator.variable if variable_name in scope: error(local_iterator.line, local_iterator_already_declared(variable_name))
def validate_variable_wrong_usage(scope, variable_node): declared_variable = scope[variable_node.variable] if type(variable_node) not in declared_variable.variable_types(): error( variable_node.line, wrong_usage(variable_node.variable, declared_variable.type_info()))