def acceptPost(request, course, exercise, post_url): ''' Presents a template and accepts post value for grading queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) fields = copy.deepcopy(exercise.get("fields", [])) if request.method == "POST": # Parse submitted values. miss = False for entry in fields: entry["value"] = request.POST.get(entry["name"], "").strip() if "required" in entry and entry["required"] and not entry["value"]: entry["missing"] = True miss = True if miss: result = {"fields": fields, "rejected": True} else: # Store submitted values. sdir = create_submission_dir(course, exercise) for entry in fields: write_submission_file(sdir, entry["name"], entry["value"]) return _acceptSubmission(request, course, exercise, post_url, sdir) else: result = {"fields": fields} return cache_headers( render_configured_template(request, course, exercise, post_url, 'access/accept_post_default.html', result), request, exercise)
def acceptGitUser(request, course, exercise, post_url): ''' Presents a template and expects a user id to create Git URL for grading. ''' auth_secret = "*AYVhD'b5,hKzf/6" _requireActions(exercise) if not "git_address" in exercise: raise ConfigError("Missing \"git_address\" in exercise configuration.") user = detect_user(request) if request.method == "POST": if user is None and "user" in request.POST and "hash" in request.POST: user = request.POST["user"] if make_hash(auth_secret, user) != request.POST["hash"]: raise PermissionDenied() source = exercise["git_address"].replace("$USER", user) sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "gitsource", source) return _acceptSubmission(request, course, exercise, post_url, sdir) return render_configured_template(request, course, exercise, post_url, "access/accept_git_user.html", { "user": user, "hash": make_hash(auth_secret, user) })
def acceptGitUser(request, course, exercise, post_url): ''' Presents a template and expects a user id to create Git URL for grading. ''' auth_secret = "*AYVhD'b5,hKzf/6" _requireActions(exercise) if not "git_address" in exercise: raise ConfigError("Missing \"git_address\" in exercise configuration.") user = get_uid(request) if request.method == "POST": if "user" in request.POST and "hash" in request.POST: user = request.POST["user"] if make_hash(auth_secret, user) != request.POST["hash"]: raise PermissionDenied() source = exercise["git_address"].replace("$USER", user) sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "gitsource", source) return _acceptSubmission(request, course, exercise, post_url, sdir) return render_configured_template(request, course, exercise, post_url, "access/accept_git_user.html", { "user": user, "hash": make_hash(auth_secret, user) })
def _saveForm(request, course, exercise, post_url, form): data, files = form.json_and_files(post_url) sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "data.json", data) for name, uploaded in files.items(): save_submitted_file(sdir, name, uploaded) return _acceptSubmission(request, course, exercise, post_url, sdir)
def _saveForm(request, course, exercise, post_url, form): data,files = form.json_and_files(post_url) sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "data.json", data) for name,uploaded in files.items(): save_submitted_file(sdir, name, uploaded) return _acceptSubmission(request, course, exercise, post_url, sdir)
def acceptGeneralForm(request, course, exercise, post_url): ''' Presents a template and accepts form containing any input types (text, file, etc) for grading queue. ''' if not_modified_since(request, exercise): return not_modified_response(request, exercise) fields = copy.deepcopy(exercise.get("fields", [])) result = None miss = False if request.method == "POST": # Parse submitted values. for entry in fields: entry["value"] = request.POST.get(entry["name"], "").strip() if "required" in entry and entry["required"] and not entry["value"]: entry["missing"] = True miss = True files_submitted = [] if "files" in exercise: # Confirm that all required files were submitted. #files_submitted = [] # exercise["files"] entries for the files that were really submitted for entry in exercise["files"]: # by default, all fields are required required = ("required" not in entry or entry["required"]) if entry["field"] not in request.FILES: if required: result = { "rejected": True, "missing_files": True } break else: files_submitted.append(entry) if miss: result = { "fields": fields, "rejected": True } elif result is None: # Store submitted values. sdir = create_submission_dir(course, exercise) for entry in fields: write_submission_file(sdir, entry["name"], entry["value"]) if "files" in exercise: if "required_number_of_files" in exercise and \ exercise["required_number_of_files"] > len(files_submitted): result = { "rejected": True, "missing_files": True } else: # Store submitted files. for entry in files_submitted: save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]]) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_general_default.html", result ), request, exercise )
def acceptAttachedExercise(request, course, exercise, post_url): ''' Accepts attached exercise rules and user files for queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST": # Search for file contents. if "file[]" in request.FILES: file_list = request.FILES.getlist("file[]") else: file_list = [] i = 0 while "content_%d" % (i) in request.FILES: file_list.append(request.FILES["content_%d" % (i)]) i += 1 # Store submitted files. if not file_list: result = { "error":True, "missing_files":True } else: sdir = create_submission_dir(course, exercise) i = 0 for content in file_list: if i > 0: key = "file_%d" % (i) if not key in request.POST or not request.POST[key]: result = { "error": True, "missing_file_name": True } clean_submission_dir(sdir) break save_submitted_file(sdir, request.POST[key], content) else: save_submitted_file(sdir, "exercise_attachment", content) i += 1 if result is None: return _acceptSubmission(request, course, exercise, post_url, sdir) # Add the attachment as a hint to the default view form. if result is None: import copy exercise = copy.deepcopy(exercise) exercise["files"] = [ { "field": "content_0", "name": "exercise_attachment" } ] return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_files_default.html", result ), request, exercise )
def acceptAttachedExercise(request, course, exercise, post_url): ''' Accepts attached exercise rules and user files for queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST": # Search for file contents. if "file[]" in request.FILES: file_list = request.FILES.getlist("file[]") else: file_list = [] i = 0 while "content_%d" % (i) in request.FILES: file_list.append(request.FILES["content_%d" % (i)]) i += 1 # Store submitted files. if not file_list: result = {"rejected": True, "missing_files": True} else: sdir = create_submission_dir(course, exercise) i = 0 for content in file_list: if i > 0: key = "file_%d" % (i) if not key in request.POST or not request.POST[key]: result = {"error": True, "missing_file_name": True} clean_submission_dir(sdir) break save_submitted_file(sdir, request.POST[key], content) else: save_submitted_file(sdir, "exercise_attachment", content) i += 1 if result is None: return _acceptSubmission(request, course, exercise, post_url, sdir) # Add the attachment as a hint to the default view form. if result is None: import copy exercise = copy.deepcopy(exercise) exercise["files"] = [{ "field": "content_0", "name": "exercise_attachment" }] return cache_headers( render_configured_template(request, course, exercise, post_url, "access/accept_files_default.html", result), request, exercise)
def acceptGitAddress(request, course, exercise, post_url): ''' Presents a template and accepts Git URL for grading. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST" and "git" in request.POST and request.POST["git"].strip(): source = request.POST["git"] # Safe gitlab addresses. if "require_gitlab" in exercise: if not source.startswith("git@%s:" % (exercise["require_gitlab"])): url_start = "https://%s/" % (exercise["require_gitlab"]) if source.startswith(url_start): url_start_len = len(url_start) url_parts = source[url_start_len:].split("/") if len(url_parts) > 1: source = "git@%s:%s/%s" % (exercise["require_gitlab"], url_parts[0], url_parts[1]) if not source.endswith(".git"): source += ".git" else: result = { "error": True, "invalid_address": True } else: result = { "error": True, "invalid_address": True } # Try to prevent shell injections. elif "\"" in source or ";" in source: result = { "error": True, "invalid_address": True } if result is None: sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "gitsource", source) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_git_default.html", result ), request, exercise )
def acceptGitAddress(request, course, exercise, post_url): ''' Presents a template and accepts Git URL for grading. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST" and "git" in request.POST and request.POST["git"].strip(): source = request.POST["git"] # Safe gitlab addresses. if "require_gitlab" in exercise: if not source.startswith("git@%s:" % (exercise["require_gitlab"])): url_start = "https://%s/" % (exercise["require_gitlab"]) if source.startswith(url_start): url_start_len = len(url_start) url_parts = source[url_start_len:].split("/") if len(url_parts) > 1: source = "git@%s:%s/%s" % (exercise["require_gitlab"], url_parts[-2], url_parts[-1]) if not source.endswith(".git"): source += ".git" else: result = { "error": True, "invalid_address": True } else: result = { "error": True, "invalid_address": True } # Try to prevent shell injections. elif "\"" in source or ";" in source: result = { "error": True, "invalid_address": True } if result is None: sdir = create_submission_dir(course, exercise) write_submission_file(sdir, "gitsource", source) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_git_default.html", result ), request, exercise )
def handle(self, *args, **options): config = ConfigParser() # Check arguments. if len(args) < 1 or "/" not in args[0]: raise CommandError("Required arguments missing: course_key/exercise_key") course_key, exercise_key = args[0].split("/", 1) # Get exercise configuration. (course, exercise) = config.exercise_entry(course_key, exercise_key) if course is None: raise CommandError("Course not found for key: %s" % (course_key)) if exercise is None: raise CommandError("Exercise not found for key: %s/%s" % (course_key, exercise_key)) self.stdout.write('Exercise configuration retrieved.') # Check exercise type. if not "actions" in exercise: raise CommandError("Cannot grade: exercise does not configure asynchronous actions") # Create submission. sdir = create_submission_dir(course, exercise) if len(args) == 1: os.makedirs(sdir + "/user") for n in range(1, len(args)): name = args[n] # Copy individual files. if os.path.isfile(name): submit_path = submission_file_path(sdir, os.path.basename(name)) shutil.copy2(name, submit_path) # Copy a directory. elif os.path.isdir(name): if len(args) != 2: raise CommandError("Can only submit one directory or multiple files.") shutil.copytree(name, sdir + "/user", True) else: raise CommandError("Submit file not found: %s" % (name)) # Run actions. r = runactions(course, exercise, sdir) self.stdout.write("Response body:") self.stdout.write(template_to_str(course, exercise, "", r["template"], r["result"]))
def acceptFiles(request, course, exercise, post_url): ''' Presents a template and accepts files for grading queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST" and "files" in exercise: # Confirm that all required files were submitted. files_submitted = [] # exercise["files"] entries for the files that were really submitted for entry in exercise["files"]: # by default, all fields are required required = ("required" not in entry or entry["required"]) if entry["field"] not in request.FILES: if required: result = { "error": True, "missing_files": True } break else: files_submitted.append(entry) if result is None: if "required_number_of_files" in exercise and \ exercise["required_number_of_files"] > len(files_submitted): result = { "error": True, "missing_files": True } else: # Store submitted files. sdir = create_submission_dir(course, exercise) for entry in files_submitted: save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]]) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_files_default.html", result ), request, exercise )
def acceptFiles(request, course, exercise, post_url): ''' Presents a template and accepts files for grading queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) result = None # Receive post. if request.method == "POST" and "files" in exercise: # Confirm that all required files were submitted. files_submitted = [] # exercise["files"] entries for the files that were really submitted for entry in exercise["files"]: # by default, all fields are required required = ("required" not in entry or entry["required"]) if entry["field"] not in request.FILES: if required: result = { "rejected": True, "missing_files": True } break else: files_submitted.append(entry) if result is None: if "required_number_of_files" in exercise and \ exercise["required_number_of_files"] > len(files_submitted): result = { "rejected": True, "missing_files": True } else: # Store submitted files. sdir = create_submission_dir(course, exercise) for entry in files_submitted: save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]]) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_files_default.html", result ), request, exercise )
def acceptPost(request, course, exercise, post_url): ''' Presents a template and accepts post value for grading queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) fields = copy.deepcopy(exercise.get("fields", [])) if request.method == "POST": # Parse submitted values. miss = False for entry in fields: entry["value"] = request.POST.get(entry["name"], "").strip() if "required" in entry and entry["required"] and not entry["value"]: entry["missing"] = True miss = True if miss: result = { "fields": fields, "error": True } else: # Store submitted values. sdir = create_submission_dir(course, exercise) for entry in fields: write_submission_file(sdir, entry["name"], entry["value"]) return _acceptSubmission(request, course, exercise, post_url, sdir) else: result = { "fields": fields } return cache_headers( render_configured_template( request, course, exercise, post_url, 'access/accept_post_default.html', result ), request, exercise )
def acceptGeneralForm(request, course, exercise, post_url): ''' Presents a template and accepts form containing any input types (text, file, etc) for grading queue. ''' _requireActions(exercise) if not_modified_since(request, exercise): return not_modified_response(request, exercise) fields = copy.deepcopy(exercise.get("fields", [])) result = None miss = False if request.method == "POST": # Parse submitted values. for entry in fields: entry["value"] = request.POST.get(entry["name"], "").strip() if "required" in entry and entry["required"] and not entry["value"]: entry["missing"] = True miss = True files_submitted = [] if "files" in exercise: # Confirm that all required files were submitted. #files_submitted = [] # exercise["files"] entries for the files that were really submitted for entry in exercise["files"]: # by default, all fields are required required = ("required" not in entry or entry["required"]) if entry["field"] not in request.FILES: if required: result = { "rejected": True, "missing_files": True } break else: files_submitted.append(entry) if miss: result = { "fields": fields, "rejected": True } elif result is None: # Store submitted values. sdir = create_submission_dir(course, exercise) for entry in fields: write_submission_file(sdir, entry["name"], entry["value"]) if "files" in exercise: if "required_number_of_files" in exercise and \ exercise["required_number_of_files"] > len(files_submitted): result = { "rejected": True, "missing_files": True } else: # Store submitted files. for entry in files_submitted: save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]]) return _acceptSubmission(request, course, exercise, post_url, sdir) return cache_headers( render_configured_template( request, course, exercise, post_url, "access/accept_general_default.html", result ), request, exercise )