refactor: assignments

This commit is contained in:
Jannat Patel
2022-10-28 19:22:48 +05:30
parent c6b917fa83
commit b3412b42b7
10 changed files with 183 additions and 63 deletions

View File

@@ -13,11 +13,16 @@
"column_break_4",
"title",
"include_in_preview",
"included_in_course",
"index_label",
"section_break_6",
"youtube",
"column_break_9",
"quiz_id",
"section_break_16",
"question",
"column_break_15",
"file_type",
"section_break_11",
"body",
"help_section",
@@ -105,11 +110,41 @@
"fieldname": "youtube",
"fieldtype": "Data",
"label": "YouTube Video URL"
},
{
"default": "0",
"fieldname": "included_in_course",
"fieldtype": "Check",
"hidden": 1,
"label": "Included in Course",
"read_only": 1
},
{
"fieldname": "section_break_16",
"fieldtype": "Section Break",
"label": "Assignment"
},
{
"description": "Assignment will appear at the bottom of the lesson.",
"fieldname": "question",
"fieldtype": "Small Text",
"label": "Question"
},
{
"fieldname": "file_type",
"fieldtype": "Select",
"label": "File Type",
"mandatory_depends_on": "question",
"options": "Image\nDocument\nPDF"
},
{
"fieldname": "column_break_15",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2022-09-02 11:30:15.450624",
"modified": "2022-10-28 12:36:01.978640",
"modified_by": "Administrator",
"module": "LMS",
"name": "Course Lesson",

View File

@@ -6,11 +6,12 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"lesson",
"user",
"column_break_3",
"assignment",
"id"
"lesson",
"course",
"column_break_3",
"member",
"member_name"
],
"fields": [
{
@@ -21,32 +22,39 @@
"label": "Lesson",
"options": "Course Lesson"
},
{
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "User",
"options": "User"
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "id",
"fieldtype": "Data",
"label": "ID"
},
{
"fieldname": "assignment",
"fieldtype": "Attach",
"label": "Assignment"
},
{
"fieldname": "member",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Member",
"options": "User"
},
{
"fetch_from": "member.full_name",
"fieldname": "member_name",
"fieldtype": "Data",
"label": "Member Name"
},
{
"fetch_from": "lesson.course",
"fieldname": "course",
"fieldtype": "Data",
"label": "Course"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-12-22 11:17:08.390615",
"modified": "2022-10-28 12:38:05.541906",
"modified_by": "Administrator",
"module": "LMS",
"name": "Lesson Assignment",
@@ -66,5 +74,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"states": []
}

View File

@@ -5,16 +5,17 @@ import frappe
from frappe.model.document import Document
from frappe.handler import upload_file
class LessonAssignment(Document):
pass
@frappe.whitelist()
def upload_assignment(assignment, lesson, identifier):
def upload_assignment(assignment, lesson):
args = {
"doctype": "Lesson Assignment",
"lesson": lesson,
"user": frappe.session.user,
"id": identifier
"member": frappe.session.user
}
if frappe.db.exists(args):
del args["doctype"]
@@ -24,18 +25,17 @@ def upload_assignment(assignment, lesson, identifier):
lesson_work = frappe.get_doc(args)
lesson_work.save(ignore_permissions=True)
@frappe.whitelist()
def get_assignment(lesson):
assignments = frappe.get_all("Lesson Assignment",
{
assignment = frappe.db.get_value("Lesson Assignment", {
"lesson": lesson,
"user": frappe.session.user
},
["lesson", "user", "id", "assignment"])
if len(assignments):
for assignment in assignments:
assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name")
return assignments
"member": frappe.session.user
}, ["lesson", "member", "assignment"],
as_dict=True)
print(assignment)
assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name")
return assignment

View File

@@ -270,7 +270,7 @@ def save_chapter(course, title, chapter_description, idx, chapter):
@frappe.whitelist()
def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None):
def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None, question=None, file_type=None):
if lesson:
doc = frappe.get_doc("Course Lesson", lesson)
else:
@@ -284,7 +284,9 @@ def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_i
"body": body,
"include_in_preview": preview,
"youtube": youtube,
"quiz_id": quiz_id
"quiz_id": quiz_id,
"question": question,
"file_type": file_type
})
doc.save(ignore_permissions=True)

View File

@@ -100,8 +100,10 @@ def get_lesson_details(chapter):
order_by="idx")
for row in lesson_list:
lesson_details = frappe.db.get_value("Course Lesson", row.lesson,
["name", "title", "include_in_preview", "body", "creation", "youtube", "quiz_id"], as_dict=True)
lesson_details = frappe.db.get_value("Course Lesson",
row.lesson,
["name", "title", "include_in_preview", "body", "creation", "youtube", "quiz_id", "question", "unique_id", "file_type"],
as_dict=True)
lesson_details.number = flt("{}.{}".format(chapter.idx, row.idx))
lesson_details.icon = "icon-list"
macros = find_macros(lesson_details.body)
@@ -244,13 +246,22 @@ def get_progress(course, lesson):
["status"])
def render_html(body, youtube, quiz_id):
def render_html(lesson):
youtube = lesson.youtube
quiz_id = lesson.quiz_id
body = lesson.body
if youtube and "/" in youtube:
youtube = youtube.split("/")[-1]
quiz_id = "{{ Quiz('" + quiz_id + "') }}" if quiz_id else ""
youtube = "{{ YouTubeVideo('" + youtube + "') }}" if youtube else ""
text = youtube + body + quiz_id
if lesson.question:
assignment = "{{ Assignment('" + lesson.question + "-" + lesson.file_type + "') }}"
text = text + assignment
return markdown_to_html(text)

View File

@@ -151,9 +151,10 @@ def assignment_renderer(detail):
"Image": ".png, .jpg, .jpeg",
"Video": "video/*"
}
question = detail.split("-")[0]
file_type = detail.split("-")[1]
accept = supported_types[file_type] if file_type else ""
return frappe.render_template("templates/assignment.html", {"id": detail.split("-")[0], "accept": accept})
return frappe.render_template("templates/assignment.html", {"question": question, "accept": accept})
def show_custom_signup():
if (frappe.db.get_single_value("LMS Settings", "terms_of_use")

View File

@@ -1126,8 +1126,7 @@ pre {
}
.preview-work {
width: 50%;
justify-content: space-between;
width: 50%;
}
.job-card {
@@ -1778,3 +1777,25 @@ li {
.course-description-section {
padding-bottom: 4rem;
}
input::file-selector-button {
border-radius: var(--border-radius);
font-size: var(--text-md);
padding: 0.25rem 1.25rem;
border: none;
color: var(--text-color);
cursor: pointer;
}
input::file-selector-button:hover {
background-color: var(--gray-400);
}
.btn {
font-weight: 400;
}
select {
appearance: none;
-webkit-appearance: none;
}

View File

@@ -1,10 +1,12 @@
<div class="form-group">
<div class="d-flex">
<input class="btn btn-default btn-sm mr-3 attach-file" type="file" id="{{ id }}" accept="{{ accept }}" />
<div class="button is-secondary submit-work">{{ _("Submit Work") }}</div>
<div class="preview-work button is-default hide">
<a target="_blank"></a>
<div class="button is-secondary clear-work">{{ _("Change") }}</div>
<div class="">
<h3> {{ _("Assignment") }} </h3>
<div class="my-3"> {{ _(question) }} </div>
<input class="btn btn-default btn-sm border attach-file" type="file" accept="{{ accept }}" />
<div class="btn btn-secondary ml-2 submit-work">{{ _("Submit") }}</div>
<div class="preview-work small hide">
<a target="_blank"></a>
<div class="btn btn-secondary btn-sm ml-2 clear-work">{{ _("Change") }}</div>
</div>
</div>
</div>
</div>

View File

@@ -123,7 +123,7 @@
{% if lesson.edit_mode %}
{{ EditLesson(lesson) }}
{% else %}
{{ render_html(lesson.body, lesson.youtube, lesson.quiz_id) }}
{{ render_html(lesson) }}
{% endif %}
{% else %}
@@ -171,11 +171,30 @@
<!-- Edit Lesson -->
{% macro EditLesson(lesson) %}
<div class="medium mt-2" contenteditable="true" data-placeholder="{{ _('YouTube Video ID') }}"
id="youtube">{% if lesson.youtube %}{{ lesson.youtube }}{% endif %}</div>
<div class="d-flex mt-2 medium">
<div class="flex-grow-1" contenteditable="true" data-placeholder="{{ _('YouTube Video ID') }}"
id="youtube">{% if lesson.youtube %}{{ lesson.youtube }}{% endif %}</div>
<div class="flex-grow-1 ml-2" contenteditable="true" data-placeholder="{{ _('Quiz ID') }}"
id="quiz-id">{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}</div>
</div>
<div id="body" {% if lesson.body %} data-body="{{ lesson.body }}" {% endif %}></div>
<div class="medium mb-4" contenteditable="true" data-placeholder="{{ _('Quiz ID') }}"
id="quiz-id">{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}</div>
<div class="d-flex medium mx-0 mb-4">
<div class="flex-grow-1" contenteditable="true" data-placeholder="{{ _('Assignment Question') }}"
id="assignment-question">{% if lesson.question %}{{ lesson.question }}{% endif %}</div>
<select class="btn btn-default ml-2" id="file-type" data-type="{{ lesson.file_type }}">
<option selected> {{ _("File Type") }} </option>
<option value="Image"> {{ _("Image") }} </option>
<option value="Document"> {{ _("Document") }} </option>
<option value="PDF"> {{ _("PDF") }} </option>
</select>
</div>
<label class="preview" for="preview">
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox" id="preview">

View File

@@ -2,6 +2,8 @@ frappe.ready(() => {
this.marked_as_complete = false;
this.quiz_submitted = false;
this.file_type;
let self = this;
localStorage.removeItem($("#quiz-title").data("name"));
@@ -9,6 +11,8 @@ frappe.ready(() => {
save_current_lesson();
set_file_type();
$(".option").click((e) => {
enable_check(e);
});
@@ -77,7 +81,6 @@ frappe.ready(() => {
});
if ($("#quiz-title").data("max-attempts")) {
let self = this;
window.addEventListener("beforeunload", (e) => {
e.returnValue = "";
if ($(".active-question").length && !self.quiz_submitted) {
@@ -89,6 +92,12 @@ frappe.ready(() => {
if ($("#body").length) {
make_editor();
}
$("#file-type").change((e) => {
$("#file-type option:selected" ).each(function() {
self.file_type = $(this).val();
});
});
});
@@ -318,8 +327,7 @@ const upload_file = (file, target) => {
let form_data = new FormData();
if (file.file_obj) {
form_data.append('file', file.file_obj, `${frappe.session.user}-${file.name}`);
form_data.append('folder', `${$(".title").attr("data-lesson")} ${$(".title").attr("data-course")}`)
form_data.append('file', file.file_obj, file.name);
}
xhr.send(form_data);
@@ -333,7 +341,6 @@ const create_lesson_work = (file, target) => {
args: {
assignment: file.file_url,
lesson: $(".title").attr("data-lesson"),
identifier: target.siblings(".attach-file").attr("id")
},
callback: (data) => {
target.siblings(".attach-file").addClass("hide");
@@ -398,17 +405,15 @@ const fetch_assignments = () => {
"lesson": $(".title").attr("data-lesson")
},
callback: (data) => {
if (data.message && data.message.length) {
const assignments = data.message;
for (let i in assignments) {
let target = $(`#${assignments[i]["id"]}`);
if (data.message) {
const assignment = data.message;
let target = $(".attach-file");
target.addClass("hide");
target.siblings(".submit-work").addClass("hide");
target.siblings(".preview-work").removeClass("hide");
target.siblings(".preview-work").find("a").attr("href", assignments[i]["assignment"]).text(assignments[i]["file_name"]);
target.siblings(".preview-work").find("a").attr("href", assignment.assignment).text(assignment.file_name);
}
}
}
});
};
@@ -449,6 +454,7 @@ const calculate_and_display_time = (percent_time) => {
const save_lesson = (e) => {
let lesson = $("#title").data("lesson");
let self = this;
frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.save_lesson",
args: {
@@ -459,7 +465,9 @@ const save_lesson = (e) => {
"chapter": $("#title").data("chapter"),
"preview": $("#preview").prop("checked") ? 1 : 0,
"idx": $("#title").data("index"),
"lesson": lesson ? lesson : ""
"lesson": lesson ? lesson : "",
"question": $("#assignment-question").text(),
"file_type": self.file_type
},
callback: (data) => {;
frappe.show_alert({
@@ -531,3 +539,15 @@ const make_editor = () => {
$("#body .frappe-control").removeClass("hide-control");
$("#body .form-column").addClass("p-0");
};
const set_file_type = () => {
let file_type = $("#file-type").data("type");
if (file_type) {
$("#file-type option").each((i, elem) => {
if ($(elem).val() == file_type) {
$(elem).attr("selected", true);
}
})
}
}