def update_submission_status(lti, lti_exception=None): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) status = request.values.get('status') course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader( submission.course_id): return ajax_failure( "This is not your submission and you are not a grader in its course." ) # Do action success = submission.update_submission_status(status) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "Submit", "answer.py", category=status, message=str(success)) return ajax_success({"success": success})
def save_assignment(lti=lti): assignment_id = request.values.get('assignment_id') user, user_id = get_user() course_id = get_course_id() assignment = Assignment.query.get(assignment_id) # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions if assignment.owner_id != user.id: require_course_grader(user, assignment.course_id) # Parse new settings updates = {} if "hidden" in request.values: updates["hidden"] = maybe_bool(request.values.get("hidden")) if "reviewed" in request.values: updates["reviewed"] = maybe_bool(request.values.get("reviewed")) if "public" in request.values: updates["public"] = maybe_bool(request.values.get("public")) if "url" in request.values: updates["url"] = request.values.get("url") or None if "ip_ranges" in request.values: updates["ip_ranges"] = request.values.get("ip_ranges") if "name" in request.values: updates["name"] = request.values.get("name") if "settings" in request.values: updates["settings"] = request.values.get("settings") # Perform update modified = assignment.edit(updates) make_log_entry(assignment.id, assignment.version, course_id or assignment.course_id, user.id, "X-Instructor.Settings.Edit", "assignment_settings.blockpy", message=json.dumps(updates)) return ajax_success({"modified": modified})
def save_student_file(filename, course_id, user): submission_id = request.values.get("submission_id") code = request.values.get("code") submission = Submission.query.get(submission_id) # Verify exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user.id: require_course_grader(user, submission.course_id) # Validate the maximum file size if app.config["MAXIMUM_CODE_SIZE"] < len(code): return ajax_failure( "Maximum size of code exceeded. Current limit is {}, you uploaded {} characters." .format(app.config["MAXIMUM_CODE_SIZE"], len(code))) # Perform update # TODO: What if submission's assignment version conflicts with current assignments' version? version_change = submission.assignment.version != submission.assignment_version submission.save_code(filename, code) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user.id, "File.Edit", "answer.py", message=code) return ajax_success({"version_change": version_change})
def load_assignment(lti=lti): # Get arguments assignment_id = int(request.values.get('assignment_id')) assignment = Assignment.by_id(assignment_id) course_id = get_course_id(True) user, user_id = get_user() # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions if course_id is None: editor_information = assignment.for_read_only_editor(user_id) else: editor_information = assignment.for_editor(user_id, course_id) browser_info = repr({ 'platform': request.user_agent.platform, 'browser': request.user_agent.browser, 'version': request.user_agent.version, 'language': request.user_agent.language, 'user_agent': request.user_agent.string }) # Log the event if user is not None: make_log_entry(assignment_id, assignment.version, course_id, user_id, 'Session.Start', message=browser_info) # Verify passcode, if necessary if assignment.passcode_fails(request.values.get('passcode')): return ajax_failure("Passcode {!r} rejected".format( request.values.get("passcode"))) return ajax_success(editor_information)
def load_assignment(lti=lti): # Get arguments assignment_id = int(request.values.get('assignment_id')) assignment = Assignment.by_id(assignment_id) student_id = maybe_int(request.values.get('user_id')) course_id = get_course_id(True) user, user_id = get_user() force_download = maybe_bool(request.values.get('force_download', "false")) # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions if user_id != student_id and not user.is_grader(course_id): return ajax_failure( "Only graders can see submissions for other people.") if course_id is None: editor_information = assignment.for_read_only_editor(student_id) else: editor_information = assignment.for_editor(student_id, course_id) browser_info = json.dumps({ 'platform': request.user_agent.platform, 'browser': request.user_agent.browser, 'version': request.user_agent.version, 'language': request.user_agent.language, 'user_agent': request.user_agent.string }) # Log the event if user is not None: if user_id != student_id: make_log_entry(assignment_id, assignment.version, course_id, user_id, 'X-Submission.Get', message=str(student_id)) else: make_log_entry(assignment_id, assignment.version, course_id, user_id, 'Session.Start', message=browser_info) # Verify passcode, if necessary if assignment.passcode_fails(request.values.get('passcode')): return ajax_failure("Passcode {!r} rejected".format( request.values.get("passcode"))) if force_download: student_filename = User.by_id(student_id).get_filename("") filename = assignment.get_filename( "") + "_" + student_filename + '_submission.json' return Response(json.dumps(editor_information), mimetype='application/json', headers={ 'Content-Disposition': 'attachment;filename={}'.format(filename) }) else: return ajax_success(editor_information)
def update_grading_status(lti, lti_exception=None): submission_id = maybe_int(request.values.get("submission_id")) # TODO: Pretty sure multiple assignments are broken for grading assignment_group_id = maybe_int(request.values.get('assignment_group_id')) new_grading_status = request.values.get("new_grading_status") user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if not user.is_grader(submission.course_id): return ajax_failure( "This is not your submission and you are not a grader in its course." ) submission.update_grading_status(new_grading_status) if submission.grading_status != GradingStatuses.FULLY_GRADED: return ajax_success({'new_status': new_grading_status}) # Do action if assignment_group_id is None: assignment_group_id = submission.assignment_group_id error = "Generic LTI Failure - perhaps not logged into LTI session?" try: success, score = lti_post_grade(lti, submission, None, assignment_group_id, submission.user_id, submission.course_id) except LTIPostMessageException as e: success = False error = str(e) if success: make_log_entry(submission.assignment_id, submission.assignment_version, submission.course_id, user_id, "X-Submission.LMS", "answer.py", message=str(score)) return ajax_success({"submitted": True, "new_status": "FullyGraded"}) else: submission.update_grading_status(GradingStatuses.FAILED) make_log_entry(submission.assignment_id, submission.assignment_version, submission.course_id, user_id, "X-Submission.LMS.Failure", "answer.py", message=error) return ajax_failure({ "submitted": False, "message": error, "new_status": "Failed" })
def save_instructor_file(course_id, user, filename): assignment_id = request.values.get("assignment_id") code = request.values.get("code") assignment = Assignment.query.get(assignment_id) # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions if assignment.owner_id != user.id: require_course_grader(user, assignment.course_id) # Perform update assignment.save_file(filename, code) make_log_entry(assignment_id, assignment.version, course_id, user.id, "X-Instructor.File.Edit", filename, message=code) return ajax_success({})
def save_image(): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) directory = request.values.get('directory') image = request.values.get('image') course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader(submission.course_id): return ajax_failure("This is not your submission and you are not a grader in its course.") # Do action success = submission.save_image(directory, image) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Image.Save", directory) return ajax_success({"success": success})
def update_submission(lti, lti_exception=None): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) lis_result_sourcedid = request.values.get('lis_result_sourcedid') assignment_group_id = maybe_int(request.values.get('assignment_group_id')) score = float(request.values.get('score', '0')) correct = maybe_bool(request.values.get("correct")) # TODO: Only send image if the assignment settings starts as Block or Split image = request.values.get('image', "") hidden_override = maybe_bool(request.values.get('hidden_override')) force_update = maybe_bool(request.values.get('force_update')) course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader(submission.course_id): return ajax_failure("This is not your submission and you are not a grader in its course.") # Do action was_changed = submission.update_submission(score, correct) if assignment_group_id is None: assignment_group_id = submission.assignment_group_id # TODO: Document that we currently only pass back grade if it changed # TODO: If failure on previous submission grading, then retry if was_changed or force_update: submission.save_block_image(image) error = "Generic LTI Failure - perhaps not logged into LTI session?" try: success, score = lti_post_grade(lti, submission, lis_result_sourcedid, assignment_group_id, submission.user_id, submission.course_id) except LTIPostMessageException as e: success = False error = str(e) if success: make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Submission.LMS", "answer.py", message=str(score)) else: submission.update_grading_status(GradingStatuses.FAILED) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Submission.LMS.Failure", "answer.py", message=error) return ajax_failure({"submitted": False, "changed": was_changed, "message": error}) return ajax_success({"submitted": was_changed or force_update, "changed": was_changed})
def log_event(lti=lti): course_id = get_course_id() user, user_id = get_user() assignment_id = request.values.get('assignment_id') assignment_version = request.values.get('assignment_version') event_type = request.values.get("event_type") file_path = request.values.get("file_path", "") category = request.values.get('category', "") label = request.values.get('label', "") message = request.values.get('message', "") # Make the entry new_log = make_log_entry(assignment_id, assignment_version, course_id, user_id, event_type, file_path, category, label, message) return ajax_success({"log_id": new_log.id})