Add functionality to parse coding assignments

pull/180/head
runtlb64 2023-09-06 01:45:44 -07:00
parent 875d888503
commit 35673f91e0
2 changed files with 184 additions and 2 deletions

View File

@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Coding Assignment</title>
<style>
body {
font-family: sf pro text, -apple-system, BlinkMacSystemFont, Roboto,
segoe ui, Helvetica, Arial, sans-serif, apple color emoji,
segoe ui emoji, segoe ui symbol;
font-weight: 400;
line-height: 22.4px;
font-size: 16px;
}
p, ul, ol {
font-size: 16px;
font-weight: 400;
}
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
}
ul {
list-style: none;
margin: 0;
padding: 0;
max-width: none;
}
.code-snippet {
background-color: #fff;
border: 1px solid #d1d7dc;
color: #b4690e;
font-size: 90%;
padding: 0.2rem 0.4rem;
}
.code-block {
background-color: #fff;
color: #b4690e;
font-size: 90%;
}
.black-block {
color: #000000;
}
.italic-text {
font-style: italic;
}
</style>
</head>
<body onload="main()">
<h1 id="coding-title"></h1>
<div>
<h2>Instructions</h2>
<div id="coding-instructions"></div>
</div>
<div>
<h2>Test(s)</h2>
<div id="coding-tests"></div>
</div>
<div>
<h2>Solution(s)</h2>
<div id="coding-solutions"></div>
</div>
<script>
const quizData = __data_placeholder__;
function renderCodeList(rootElement, codeList, className, titlePrefix) {
for (var i = 0; i < codeList.length; i++) {
var elem = codeList[i];
var jsElem = document.createElement("div");
jsElem.className = className;
var jsElemTitle = document.createElement("h3");
jsElemTitle.innerHTML = titlePrefix + " " + (i + 1);
var jsElemBody = document.createElement("code");
jsElemBody.className = "code-block black-block";
jsElemBody.innerHTML = "<pre>" + elem.content + "</pre>";
jsElem.appendChild(jsElemTitle);
jsElem.appendChild(jsElemBody);
rootElement.appendChild(jsElem);
}
}
function main() {
// display the assignment
var codingTitle = document.getElementById("coding-title");
codingTitle.innerHTML = quizData.title;
var codingInstructions = document.getElementById("coding-instructions");
if (quizData.hasInstructions) {
codingInstructions.innerHTML = quizData.instructions;
} else {
codingInstructions.innerHTML = "<span class=\"italic-text\">" + quizData.instructions
+ "</span>";
}
// display the test(s)
var codingTests = document.getElementById("coding-tests");
if (!quizData.hasTests) {
codingTests.innerHTML = "<span class=\"italic-text\">" + quizData.tests + "</span>";
} else {
renderCodeList(codingTests, quizData.tests, "coding-test", "Test");
}
// display the solution(s)
var codingSolutions = document.getElementById("coding-solutions");
if (!quizData.hasSolutions) {
codingSolutions.innerHTML = "<span class=\"italic-text\">" + quizData.solutions + "</span>";
} else {
renderCodeList(codingSolutions, quizData.solutions, "coding-solution", "Solution");
}
}
</script>
</body>
</html>

68
main.py
View File

@ -385,6 +385,38 @@ class Udemy:
sys.exit(1)
else:
return resp.get("results")
def _get_elem_value_or_none(self, elem, key):
return elem[key] if elem and key in elem else "(None)"
def _get_quiz_with_info(self, quiz_id):
resp = { "_class": None, "_type": None, "contents": None }
quiz_json = self._get_quiz(quiz_id)
is_only_one = len(quiz_json) == 1 and quiz_json[0]["_class"] == "assessment"
is_coding_assignment = quiz_json[0]["assessment_type"] == "coding-problem"
resp["_class"] = quiz_json[0]["_class"]
if is_only_one and is_coding_assignment:
assignment = quiz_json[0]
prompt = assignment["prompt"]
resp["_type"] = assignment["assessment_type"]
resp["contents"] = {
"instructions": self._get_elem_value_or_none(prompt, "instructions"),
"tests": self._get_elem_value_or_none(prompt, "test_files"),
"solutions": self._get_elem_value_or_none(prompt, "solution_files"),
}
resp["hasInstructions"] = False if resp["contents"]["instructions"] == "(None)" else True
resp["hasTests"] = False if isinstance(resp["contents"]["tests"], str) else True
resp["hasSolutions"] = False if isinstance(resp["contents"]["solutions"], str) else True
else: # Normal quiz
resp["_type"] = "normal-quiz"
resp["contents"] = quiz_json
return resp
def _extract_supplementary_assets(self, supp_assets, lecture_counter):
_temp = []
@ -1606,18 +1638,50 @@ def process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir):
def process_quiz(udemy: Udemy, lecture, chapter_dir):
quiz = udemy._get_quiz_with_info(lecture.get("id"))
if quiz["_type"] == "coding-problem":
process_coding_assignment(quiz, lecture, chapter_dir)
else: # Normal quiz
process_normal_quiz(quiz, lecture, chapter_dir)
def process_normal_quiz(quiz, lecture, chapter_dir):
lecture_title = lecture.get("lecture_title")
lecture_index = lecture.get("lecture_index")
lecture_file_name = sanitize_filename(lecture_title + ".html")
lecture_path = os.path.join(chapter_dir, lecture_file_name)
logger.info(f" > Processing quiz {lecture_index}")
questions = udemy._get_quiz(lecture.get("id"))
with open("quiz_template.html", "r") as f:
html = f.read()
quiz_data = {
"pass_percent": lecture.get("data").get("pass_percent"),
"questions": questions,
"questions": quiz["contents"],
}
html = html.replace("__data_placeholder__", json.dumps(quiz_data))
with open(lecture_path, "w") as f:
f.write(html)
def process_coding_assignment(quiz, lecture, chapter_dir):
lecture_title = lecture.get("lecture_title")
lecture_index = lecture.get("lecture_index")
lecture_file_name = sanitize_filename(lecture_title + ".html")
lecture_path = os.path.join(chapter_dir, lecture_file_name)
logger.info(f" > Processing quiz {lecture_index} (coding assignment)")
with open("coding_assignment_template.html", "r") as f:
html = f.read()
quiz_data = {
"title": lecture_title,
"hasInstructions": quiz["hasInstructions"],
"hasTests": quiz["hasTests"],
"hasSolutions": quiz["hasSolutions"],
"instructions": quiz["contents"]["instructions"],
"tests": quiz["contents"]["tests"],
"solutions": quiz["contents"]["solutions"],
}
html = html.replace("__data_placeholder__", json.dumps(quiz_data))
with open(lecture_path, "w") as f: