def children_recursion(parent): if not "children" in parent: return [] result = [] for o in [o for o in parent["children"] if "key" in o]: of = _type_dict(o, course.get("exercise_types", {})) if "config" in of: _, exercise = config.exercise_entry(course["key"], str(of["key"]), '_root') of = export.exercise(request, course, exercise, of) elif "static_content" in of: of = export.chapter(request, course, of) of["children"] = children_recursion(o) result.append(of) return result
def configure(request): ''' Configure a course according to the gitmanager protocol. ''' if request.method != "POST": return HttpResponse(status=405) if request.POST.get("publish"): return publish(request) if "exercises" not in request.POST or "course_id" not in request.POST: return HttpResponse("Missing exercises or course_id", status=400) try: exercises = json.loads(request.POST["exercises"]) except (JSONDecodeError, ValueError) as e: LOGGER.info(f"Invalid exercises field: {e}") return HttpResponse(f"Invalid exercises field: {e}", status=400) course_id = request.POST["course_id"] try: access_write_check(request, course_id) except PermissionDenied as e: SecurityLog.reject(request, f"CONFIGURE", f"course_id={course_id}: {e}") raise except ValueError as e: LOGGER.info(f"Invalid course_id field: {e}") return HttpResponse(f"Invalid course_id field: {e}", status=400) SecurityLog.accept(request, f"CONFIGURE", f"course_id={course_id}") root_dir = Path(settings.COURSE_STORE) course_path = root_dir / course_id if course_path.exists(): try: rmtree(course_path) except OSError: LOGGER.exception("Failed to remove old stored course files") return HttpResponse("Failed to remove old stored course files", status=500) course_files_path = course_path / EXTERNAL_FILES_DIR course_exercises_path = course_path / EXTERNAL_EXERCISES_DIR version_id_path = root_dir / (course_id + ".version") course_files_path.mkdir(parents=True, exist_ok=True) course_exercises_path.mkdir(parents=True, exist_ok=True) if "files" in request.FILES: tar_file = request.FILES["files"].file tarh = TarFile(fileobj=tar_file) tarh.extractall(course_files_path) course_config = { "name": course_id, "exercises": [ex["key"] for ex in exercises], "exercise_loader": "access.config._ext_exercise_loader", } try: with open(course_path / "index.json", "w") as f: json.dump(course_config, f) for info in exercises: with open(course_exercises_path / (info["key"] + ".json"), "w") as f: json.dump(info["config"], f) except OSError as e: LOGGER.exception("Failed to dump configuration JSONs to files") return HttpResponse("Failed to dump configuration JSONs to files: {e}", status=500) if "version_id" in request.POST: try: with open(version_id_path, "w") as f: f.write(request.POST["version_id"]) except OSError as e: LOGGER.exception("Failed to write version id file") return HttpResponse("Failed to write version id file: {e}", status=500) elif version_id_path.exists(): try: rm_path(version_id_path) except OSError as e: LOGGER.exception("Failed to remove version id file") return HttpResponse("Failed to remove version id file: {e}", status=500) course_config = config._course_root_from_root_dir(course_id, root_dir) defaults = {} for info in exercises: of = info["spec"] if info.get("config"): of["config"] = info["key"] + ".json" course, exercise = config.exercise_entry(course_config, info["key"], "_root") of = export.exercise(request, course, exercise, of) defaults[of["key"]] = of return JsonResponse(defaults)