Merge pull request #279 from pateljannat/upload-in-lessons
This commit is contained in:
@@ -202,7 +202,8 @@ school_markdown_macro_renderers = {
|
|||||||
"Exercise": "school.plugins.exercise_renderer",
|
"Exercise": "school.plugins.exercise_renderer",
|
||||||
"Quiz": "school.plugins.quiz_renderer",
|
"Quiz": "school.plugins.quiz_renderer",
|
||||||
"YouTubeVideo": "school.plugins.youtube_video_renderer",
|
"YouTubeVideo": "school.plugins.youtube_video_renderer",
|
||||||
"Video": "school.plugins.video_renderer"
|
"Video": "school.plugins.video_renderer",
|
||||||
|
"Assignment": "school.plugins.assignment_renderer"
|
||||||
}
|
}
|
||||||
|
|
||||||
# page_renderer to manage profile pages
|
# page_renderer to manage profile pages
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ frappe.ui.form.on('Course Lesson', {
|
|||||||
frm.get_field('help').html(`
|
frm.get_field('help').html(`
|
||||||
<p>You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same.</p>
|
<p>You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same.</p>
|
||||||
<div class="row font-weight-bold mb-3">
|
<div class="row font-weight-bold mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
Content Type
|
Content Type
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
@@ -18,7 +18,7 @@ frappe.ui.form.on('Course Lesson', {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
Video
|
Video
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
@@ -27,7 +27,7 @@ frappe.ui.form.on('Course Lesson', {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
YouTube Video
|
YouTube Video
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
@@ -36,7 +36,7 @@ frappe.ui.form.on('Course Lesson', {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
Exercise
|
Exercise
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
@@ -45,13 +45,60 @@ frappe.ui.form.on('Course Lesson', {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
Quiz
|
Quiz
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
{{ Quiz("lms_quiz_name") }}
|
{{ Quiz("lms_quiz_name") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
Assignment
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
{{ Assignment("id-filetype") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="row font-weight-bold mb-3">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
Supported File Types for Assignment
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
Syntax
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
.doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
Document
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
.pdf
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
PDF
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
.png, .jpg, .jpeg
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
Image
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ from frappe.model.document import Document
|
|||||||
from ...md import markdown_to_html, find_macros
|
from ...md import markdown_to_html, find_macros
|
||||||
|
|
||||||
class CourseLesson(Document):
|
class CourseLesson(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.check_and_create_folder()
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
dynamic_documents = ["Exercise", "Quiz"]
|
dynamic_documents = ["Exercise", "Quiz"]
|
||||||
for section in dynamic_documents:
|
for section in dynamic_documents:
|
||||||
@@ -43,8 +46,18 @@ class CourseLesson(Document):
|
|||||||
ex.index_label = ""
|
ex.index_label = ""
|
||||||
ex.save()
|
ex.save()
|
||||||
|
|
||||||
|
def check_and_create_folder(self):
|
||||||
|
course = frappe.db.get_value("Chapter", self.chapter, "course")
|
||||||
|
args = {
|
||||||
|
"doctype": "File",
|
||||||
|
"is_folder": True,
|
||||||
|
"file_name": f"{self.name} {course}"
|
||||||
|
}
|
||||||
|
if not frappe.db.exists(args):
|
||||||
|
folder = frappe.get_doc(args)
|
||||||
|
folder.save(ignore_permissions=True)
|
||||||
|
|
||||||
def render_html(self):
|
def render_html(self):
|
||||||
print(self.body)
|
|
||||||
return markdown_to_html(self.body)
|
return markdown_to_html(self.body)
|
||||||
|
|
||||||
def get_exercises(self):
|
def get_exercises(self):
|
||||||
|
|||||||
0
school/lms/doctype/lesson_assignment/__init__.py
Normal file
0
school/lms/doctype/lesson_assignment/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2021, Frappe and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Lesson Assignment', {
|
||||||
|
// refresh: function(frm) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
});
|
||||||
70
school/lms/doctype/lesson_assignment/lesson_assignment.json
Normal file
70
school/lms/doctype/lesson_assignment/lesson_assignment.json
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2021-12-21 16:15:22.651658",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"lesson",
|
||||||
|
"user",
|
||||||
|
"column_break_3",
|
||||||
|
"assignment",
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "lesson",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-12-22 11:17:08.390615",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "LMS",
|
||||||
|
"name": "Lesson Assignment",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
|
}
|
||||||
43
school/lms/doctype/lesson_assignment/lesson_assignment.py
Normal file
43
school/lms/doctype/lesson_assignment/lesson_assignment.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Copyright (c) 2021, Frappe and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
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):
|
||||||
|
args = {
|
||||||
|
"doctype": "Lesson Assignment",
|
||||||
|
"lesson": lesson,
|
||||||
|
"user": frappe.session.user,
|
||||||
|
"id": identifier
|
||||||
|
}
|
||||||
|
if frappe.db.exists(args):
|
||||||
|
del args["doctype"]
|
||||||
|
frappe.db.set_value("Lesson Assignment", args, "assignment", assignment)
|
||||||
|
else:
|
||||||
|
args.update({"assignment": assignment})
|
||||||
|
lesson_work = frappe.get_doc(args)
|
||||||
|
lesson_work.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_assignment(lesson):
|
||||||
|
assignments = frappe.get_all("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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2021, Frappe and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestLessonAssignment(unittest.TestCase):
|
||||||
|
pass
|
||||||
@@ -121,6 +121,17 @@ def youtube_video_renderer(video_id):
|
|||||||
def video_renderer(src):
|
def video_renderer(src):
|
||||||
return "<video controls width='100%'><source src={0} type='video/mp4'></video>".format(src)
|
return "<video controls width='100%'><source src={0} type='video/mp4'></video>".format(src)
|
||||||
|
|
||||||
|
def assignment_renderer(detail):
|
||||||
|
supported_types = {
|
||||||
|
"Document": ".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
"PDF": ".pdf",
|
||||||
|
"Image": ".png, .jpg, .jpeg",
|
||||||
|
"Video": "video/*"
|
||||||
|
}
|
||||||
|
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})
|
||||||
|
|
||||||
def show_custom_signup():
|
def show_custom_signup():
|
||||||
if frappe.db.get_single_value("LMS Settings", "terms_of_use"):
|
if frappe.db.get_single_value("LMS Settings", "terms_of_use"):
|
||||||
return "school/templates/signup-form.html"
|
return "school/templates/signup-form.html"
|
||||||
|
|||||||
@@ -1458,3 +1458,8 @@ pre {
|
|||||||
.no-discussions {
|
.no-discussions {
|
||||||
width: 80% !important;
|
width: 80% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-work {
|
||||||
|
width: 50%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|||||||
10
school/templates/assignment.html
Normal file
10
school/templates/assignment.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
|
|
||||||
localStorage.removeItem($("#quiz-title").text());
|
localStorage.removeItem($("#quiz-title").text());
|
||||||
|
fetch_assignments();
|
||||||
|
|
||||||
save_current_lesson();
|
save_current_lesson();
|
||||||
|
|
||||||
@@ -34,26 +35,34 @@ frappe.ready(() => {
|
|||||||
|
|
||||||
$("#certification").click((e) => {
|
$("#certification").click((e) => {
|
||||||
create_certificate(e);
|
create_certificate(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".submit-work").click((e) => {
|
||||||
|
attach_work(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".clear-work").click((e) => {
|
||||||
|
clear_work(e);
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
});
|
||||||
|
|
||||||
var save_current_lesson = () => {
|
const save_current_lesson = () => {
|
||||||
if ($(".title").hasClass("is-member")) {
|
if ($(".title").hasClass("is-member")) {
|
||||||
frappe.call("school.lms.api.save_current_lesson", {
|
frappe.call("school.lms.api.save_current_lesson", {
|
||||||
course_name: $(".title").attr("data-course"),
|
course_name: $(".title").attr("data-course"),
|
||||||
lesson_name: $(".title").attr("data-lesson")
|
lesson_name: $(".title").attr("data-lesson")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var enable_check = (e) => {
|
const enable_check = (e) => {
|
||||||
if ($(".option:checked").length && $("#check").attr("disabled")) {
|
if ($(".option:checked").length && $("#check").attr("disabled")) {
|
||||||
$("#check").removeAttr("disabled");
|
$("#check").removeAttr("disabled");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var mark_active_question = (e = undefined) => {
|
const mark_active_question = (e = undefined) => {
|
||||||
var current_index;
|
var current_index;
|
||||||
var next_index = 1;
|
var next_index = 1;
|
||||||
if (e) {
|
if (e) {
|
||||||
@@ -67,9 +76,9 @@ var mark_active_question = (e = undefined) => {
|
|||||||
$("#check").removeClass("hide").attr("disabled", true);
|
$("#check").removeClass("hide").attr("disabled", true);
|
||||||
$("#next").addClass("hide");
|
$("#next").addClass("hide");
|
||||||
$(".explanation").addClass("hide");
|
$(".explanation").addClass("hide");
|
||||||
}
|
};
|
||||||
|
|
||||||
var mark_progress = (e) => {
|
const mark_progress = (e) => {
|
||||||
/* Prevent default only for Next button anchor tag and not for progress checkbox */
|
/* Prevent default only for Next button anchor tag and not for progress checkbox */
|
||||||
if ($(e.currentTarget).prop("nodeName") != "INPUT")
|
if ($(e.currentTarget).prop("nodeName") != "INPUT")
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -101,9 +110,9 @@ var mark_progress = (e) => {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
move_to_next_lesson(e);
|
move_to_next_lesson(e);
|
||||||
}
|
};
|
||||||
|
|
||||||
var change_progress_indicators = (status, e) => {
|
const change_progress_indicators = (status, e) => {
|
||||||
if (status == "Complete") {
|
if (status == "Complete") {
|
||||||
$(".lesson-progress").removeClass("hide");
|
$(".lesson-progress").removeClass("hide");
|
||||||
$(".active-lesson .lesson-progress-tick").removeClass("hide");
|
$(".active-lesson .lesson-progress-tick").removeClass("hide");
|
||||||
@@ -116,22 +125,22 @@ var change_progress_indicators = (status, e) => {
|
|||||||
$(e.currentTarget).addClass("hide");
|
$(e.currentTarget).addClass("hide");
|
||||||
$("input.mark-progress").prop("checked", false).closest(".custom-checkbox").removeClass("hide");
|
$("input.mark-progress").prop("checked", false).closest(".custom-checkbox").removeClass("hide");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const show_certificate_if_course_completed = (data) => {
|
const show_certificate_if_course_completed = (data) => {
|
||||||
if (data.message == 100 && !$(".next").attr("data-next") && $("#certification").hasClass("hide")) {
|
if (data.message == 100 && !$(".next").attr("data-next") && $("#certification").hasClass("hide")) {
|
||||||
$("#certification").removeClass("hide");
|
$("#certification").removeClass("hide");
|
||||||
$(".next").addClass("hide");
|
$(".next").addClass("hide");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const move_to_next_lesson = (e) => {
|
const move_to_next_lesson = (e) => {
|
||||||
if ($(e.currentTarget).hasClass("next") && $(e.currentTarget).attr("data-href")) {
|
if ($(e.currentTarget).hasClass("next") && $(e.currentTarget).attr("data-href")) {
|
||||||
window.location.href = $(e.currentTarget).attr("data-href");
|
window.location.href = $(e.currentTarget).attr("data-href");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var quiz_summary = (e) => {
|
const quiz_summary = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var quiz_name = $("#quiz-title").text();
|
var quiz_name = $("#quiz-title").text();
|
||||||
var total_questions = $(".question").length;
|
var total_questions = $(".question").length;
|
||||||
@@ -152,13 +161,13 @@ var quiz_summary = (e) => {
|
|||||||
$("#try-again").removeClass("hide");
|
$("#try-again").removeClass("hide");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
};
|
||||||
|
|
||||||
var try_quiz_again = (e) => {
|
const try_quiz_again = (e) => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
};
|
||||||
|
|
||||||
var check_answer = (e) => {
|
const check_answer = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var quiz_name = $("#quiz-title").text();
|
var quiz_name = $("#quiz-title").text();
|
||||||
@@ -182,9 +191,9 @@ var check_answer = (e) => {
|
|||||||
|
|
||||||
var [answer, is_correct] = parse_options();
|
var [answer, is_correct] = parse_options();
|
||||||
add_to_local_storage(quiz_name, current_index, answer, is_correct)
|
add_to_local_storage(quiz_name, current_index, answer, is_correct)
|
||||||
}
|
};
|
||||||
|
|
||||||
var parse_options = () => {
|
const parse_options = () => {
|
||||||
var answer = [];
|
var answer = [];
|
||||||
var is_correct = [];
|
var is_correct = [];
|
||||||
$(".active-question input").each((i, element) => {
|
$(".active-question input").each((i, element) => {
|
||||||
@@ -200,14 +209,14 @@ var parse_options = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return [answer, is_correct];
|
return [answer, is_correct];
|
||||||
}
|
};
|
||||||
|
|
||||||
var add_icon = (element, icon) => {
|
const add_icon = (element, icon) => {
|
||||||
var label = $(element).parent().find(".label-area p").text();
|
var label = $(element).parent().find(".label-area p").text();
|
||||||
$(element).parent().empty().html(`<img class="mr-3" src="/assets/school/icons/${icon}.svg"> ${label}`);
|
$(element).parent().empty().html(`<img class="mr-3" src="/assets/school/icons/${icon}.svg"> ${label}`);
|
||||||
}
|
};
|
||||||
|
|
||||||
var add_to_local_storage = (quiz_name, current_index, answer, is_correct) => {
|
const add_to_local_storage = (quiz_name, current_index, answer, is_correct) => {
|
||||||
var quiz_stored = JSON.parse(localStorage.getItem(quiz_name));
|
var quiz_stored = JSON.parse(localStorage.getItem(quiz_name));
|
||||||
var quiz_obj = {
|
var quiz_obj = {
|
||||||
"question_index": current_index,
|
"question_index": current_index,
|
||||||
@@ -216,9 +225,9 @@ var add_to_local_storage = (quiz_name, current_index, answer, is_correct) => {
|
|||||||
}
|
}
|
||||||
quiz_stored ? quiz_stored.push(quiz_obj) : quiz_stored = [quiz_obj]
|
quiz_stored ? quiz_stored.push(quiz_obj) : quiz_stored = [quiz_obj]
|
||||||
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored))
|
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored))
|
||||||
}
|
};
|
||||||
|
|
||||||
var create_certificate = (e) => {
|
const create_certificate = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
course = $(".title").attr("data-course");
|
course = $(".title").attr("data-course");
|
||||||
frappe.call({
|
frappe.call({
|
||||||
@@ -230,4 +239,132 @@ var create_certificate = (e) => {
|
|||||||
window.location.href = `/courses/${course}/${data.message}`;
|
window.location.href = `/courses/${course}/${data.message}`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const attach_work = (e) => {
|
||||||
|
const target = $(e.currentTarget);
|
||||||
|
let files = target.siblings(".attach-file").prop("files")
|
||||||
|
if (files && files.length) {
|
||||||
|
files = add_files(files)
|
||||||
|
return_as_dataurl(files)
|
||||||
|
files.map((file) => {
|
||||||
|
upload_file(file, target);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const upload_file = (file, target) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
let response = JSON.parse(xhr.responseText)
|
||||||
|
create_lesson_work(response.message, target);
|
||||||
|
} else if (xhr.status === 403) {
|
||||||
|
let response = JSON.parse(xhr.responseText);
|
||||||
|
frappe.msgprint(`Not permitted. ${response._error_message || ''}`);
|
||||||
|
|
||||||
|
} else if (xhr.status === 413) {
|
||||||
|
frappe.msgprint('Size exceeds the maximum allowed file size.');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(xhr.status === 0 ? 'XMLHttpRequest Error' : `${xhr.status} : ${xhr.statusText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.open('POST', '/api/method/upload_file', true);
|
||||||
|
xhr.setRequestHeader('Accept', 'application/json');
|
||||||
|
xhr.setRequestHeader('X-Frappe-CSRF-Token', frappe.csrf_token);
|
||||||
|
|
||||||
|
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")}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send(form_data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const create_lesson_work = (file, target) => {
|
||||||
|
frappe.call({
|
||||||
|
method: "school.lms.doctype.lesson_assignment.lesson_assignment.upload_assignment",
|
||||||
|
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");
|
||||||
|
target.siblings(".preview-work").removeClass("hide");
|
||||||
|
target.siblings(".preview-work").find("a").attr("href", file.file_url).text(file.file_name)
|
||||||
|
target.addClass("hide");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const return_as_dataurl = (files) => {
|
||||||
|
let promises = files.map(file =>
|
||||||
|
frappe.dom.file_to_base64(file.file_obj)
|
||||||
|
.then(dataurl => {
|
||||||
|
file.dataurl = dataurl;
|
||||||
|
this.on_success && this.on_success(file);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
const add_files = (files) => {
|
||||||
|
files = Array.from(files).map(file => {
|
||||||
|
let is_image = file.type.startsWith('image');
|
||||||
|
return {
|
||||||
|
file_obj: file,
|
||||||
|
cropper_file: file,
|
||||||
|
crop_box_data: null,
|
||||||
|
optimize: this.attach_doc_image ? true : false,
|
||||||
|
name: file.name,
|
||||||
|
doc: null,
|
||||||
|
progress: 0,
|
||||||
|
total: 0,
|
||||||
|
failed: false,
|
||||||
|
request_succeeded: false,
|
||||||
|
error_message: null,
|
||||||
|
uploading: false,
|
||||||
|
private: !is_image
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return files
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear_work = (e) => {
|
||||||
|
const target = $(e.currentTarget);
|
||||||
|
const parent = target.closest(".preview-work");
|
||||||
|
parent.addClass("hide");
|
||||||
|
parent.siblings(".attach-file").removeClass("hide").val(null);
|
||||||
|
parent.siblings(".submit-work").removeClass("hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetch_assignments = () => {
|
||||||
|
if ($(".attach-file").length > 0) {
|
||||||
|
frappe.call({
|
||||||
|
method: "school.lms.doctype.lesson_assignment.lesson_assignment.get_assignment",
|
||||||
|
args: {
|
||||||
|
"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"]}`);
|
||||||
|
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"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user