Compare commits
2 Commits
web-form-c
...
certificat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff1363b437 | ||
|
|
952e3a9906 |
@@ -134,7 +134,7 @@ fixtures = ["Custom Field"]
|
|||||||
website_route_rules = [
|
website_route_rules = [
|
||||||
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
||||||
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
||||||
{"from_route": "/courses/<course>/<topic>", "to_route": "courses/topic"},
|
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
|
||||||
{"from_route": "/hackathons/<hackathon>", "to_route": "hackathons/hackathon"},
|
{"from_route": "/hackathons/<hackathon>", "to_route": "hackathons/hackathon"},
|
||||||
{"from_route": "/hackathons/<hackathon>/<project>", "to_route": "hackathons/project"},
|
{"from_route": "/hackathons/<hackathon>/<project>", "to_route": "hackathons/project"},
|
||||||
{"from_route": "/add-a-new-batch", "to_route": "add-a-new-batch"},
|
{"from_route": "/add-a-new-batch", "to_route": "add-a-new-batch"},
|
||||||
@@ -175,4 +175,5 @@ community_markdown_macro_renderers = {
|
|||||||
"Exercise": "community.plugins.exercise_renderer",
|
"Exercise": "community.plugins.exercise_renderer",
|
||||||
"Quiz": "community.plugins.quiz_renderer",
|
"Quiz": "community.plugins.quiz_renderer",
|
||||||
"YouTubeVideo": "community.plugins.youtube_video_renderer",
|
"YouTubeVideo": "community.plugins.youtube_video_renderer",
|
||||||
|
"Video": "community.plugins.video_renderer"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ frappe.ui.form.on('Lesson', {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
Video
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
{{ Video("url_of_source") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
YouTube Video
|
YouTube Video
|
||||||
|
|||||||
@@ -29,13 +29,17 @@ def create_certificate(course):
|
|||||||
return certificate
|
return certificate
|
||||||
|
|
||||||
else:
|
else:
|
||||||
expires_after_yrs = course_details.expiry
|
expires_after_yrs = int(course_details.expiry)
|
||||||
|
expiry_date = None
|
||||||
|
if expires_after_yrs:
|
||||||
|
expiry_date = add_years(nowdate(), expires_after_yrs)
|
||||||
|
|
||||||
certificate = frappe.get_doc({
|
certificate = frappe.get_doc({
|
||||||
"doctype": "LMS Certification",
|
"doctype": "LMS Certification",
|
||||||
"student": frappe.session.user,
|
"student": frappe.session.user,
|
||||||
"course": course,
|
"course": course,
|
||||||
"issue_date": nowdate(),
|
"issue_date": nowdate(),
|
||||||
"expiry_date": add_years(nowdate(), int(expires_after_yrs))
|
"expiry_date": expiry_date
|
||||||
})
|
})
|
||||||
certificate.save(ignore_permissions=True)
|
certificate.save(ignore_permissions=True)
|
||||||
return certificate.name
|
return certificate.name
|
||||||
|
|||||||
@@ -29,7 +29,10 @@
|
|||||||
"section_break_5",
|
"section_break_5",
|
||||||
"short_introduction",
|
"short_introduction",
|
||||||
"description",
|
"description",
|
||||||
"chapters"
|
"chapters",
|
||||||
|
"certification_section",
|
||||||
|
"enable_certification",
|
||||||
|
"expiry"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -119,6 +122,25 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_11",
|
"fieldname": "column_break_11",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "certification_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Certification"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enable_certification",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Certification"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "enable_certification",
|
||||||
|
"fieldname": "expiry",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Certification Expires After Years",
|
||||||
|
"options": "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
@@ -140,7 +162,7 @@
|
|||||||
"link_fieldname": "course"
|
"link_fieldname": "course"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-08-20 11:01:15.795219",
|
"modified": "2021-08-25 11:04:57.211898",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Course",
|
"name": "LMS Course",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import markdown
|
|||||||
from markdown import Extension
|
from markdown import Extension
|
||||||
from markdown.inlinepatterns import InlineProcessor
|
from markdown.inlinepatterns import InlineProcessor
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
|
import html as HTML
|
||||||
|
|
||||||
def markdown_to_html(text):
|
def markdown_to_html(text):
|
||||||
"""Renders markdown text into html.
|
"""Renders markdown text into html.
|
||||||
@@ -109,4 +110,5 @@ def sanitize_html(html, macro):
|
|||||||
classname = ""
|
classname = ""
|
||||||
if macro == "YouTubeVideo":
|
if macro == "YouTubeVideo":
|
||||||
classname = "lesson-video"
|
classname = "lesson-video"
|
||||||
|
|
||||||
return "<div class='" + classname + "'>" + "\n".join(str(node) for node in nodes) + "</div>"
|
return "<div class='" + classname + "'>" + "\n".join(str(node) for node in nodes) + "</div>"
|
||||||
|
|||||||
@@ -106,3 +106,6 @@ def youtube_video_renderer(video_id):
|
|||||||
allowfullscreen>
|
allowfullscreen>
|
||||||
</iframe>
|
</iframe>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def video_renderer(src):
|
||||||
|
return "<video controls width='100%'><source src={0} type='video/mp4'></video>".format(src)
|
||||||
|
|||||||
@@ -1414,17 +1414,24 @@ textarea.form-control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.certificate-page .common-card-style {
|
.certificate-page .common-card-style {
|
||||||
flex-direction: column;
|
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 2rem;
|
width: 40%;
|
||||||
text-align: center;
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate-content {
|
||||||
padding: 5rem;
|
padding: 5rem;
|
||||||
background-image: url(/assets/community/images/certificate-background.png);
|
}
|
||||||
|
|
||||||
|
.certificate-ribbon {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
margin-right: 2rem;
|
||||||
|
width: 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-heading {
|
.certificate-heading {
|
||||||
font-size: 4rem;
|
font-size: 2rem;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -1433,18 +1440,47 @@ textarea.form-control {
|
|||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.certificate-logo {
|
||||||
|
height: 20px;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.certificate-content {
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.certificate-page .common-card-style {
|
.certificate-page .common-card-style {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate-content {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-heading {
|
.certificate-ribbon {
|
||||||
font-size: 3rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.certificate-heading {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 550px) {
|
||||||
|
.certificate-page .common-card-style {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.certificate-page .common-card-style {
|
||||||
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 360px) {
|
|
||||||
.certificate-heading {
|
.certificate-heading {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<div class="common-card-style">
|
<div class="common-card-style">
|
||||||
|
<div class="certificate-content">
|
||||||
<div class="certificate-heading">
|
<div class="certificate-heading">
|
||||||
Certificate of Completion
|
Certificate of Completion
|
||||||
</div>
|
</div>
|
||||||
@@ -7,26 +8,28 @@
|
|||||||
<span class="font-weight-bold">{{ course.title }}</span> online course on
|
<span class="font-weight-bold">{{ course.title }}</span> online course on
|
||||||
<span class="font-weight-bold">{{ frappe.utils.format_date(certificate.issue_date, "medium") }}</span>
|
<span class="font-weight-bold">{{ frappe.utils.format_date(certificate.issue_date, "medium") }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; justify-content: space-between;" class="certificate-footer">
|
<div class="certificate-footer">
|
||||||
<div>
|
<div>
|
||||||
<div class="font-weight-bold">
|
<span>
|
||||||
Instructor:
|
Instructor:
|
||||||
</div>
|
</span>
|
||||||
<div>
|
<span class="font-weight-bold">
|
||||||
{{ instructor.full_name }}
|
{{ instructor.full_name }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% if certificate.expiry_date %}
|
||||||
<div>
|
<div>
|
||||||
<div class="font-weight-bold">
|
<span>
|
||||||
Expiry Date:
|
Expiry Date:
|
||||||
</div>
|
</span>
|
||||||
<div>
|
<span class="font-weight-bold">
|
||||||
{{ frappe.utils.format_date(certificate.expiry_date, "medium") }}
|
{{ frappe.utils.format_date(certificate.expiry_date, "medium") }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<img src="{{ logo }}" class="certificate-logo">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="certificate-ribbon"></div>
|
||||||
<img src="{{ logo }}" style="height: 50px;">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<script src="/assets/community/js/html2canvas.js"></script>
|
<script src="/assets/community/js/html2canvas.js"></script>
|
||||||
|
|||||||
@@ -26,9 +26,8 @@
|
|||||||
<div class="custom-checkbox">
|
<div class="custom-checkbox">
|
||||||
<label class="quiz-label">
|
<label class="quiz-label">
|
||||||
<input class="option" value="{{ option | urlencode }}"
|
<input class="option" value="{{ option | urlencode }}"
|
||||||
data-correct="{{ question['is_correct_' + loop.index | string] }}"
|
data-correct="{{ question['is_correct_' + loop.index | string] }}" {% if question.multiple %}
|
||||||
{% if question.multiple %} type="checkbox"
|
type="checkbox" {% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}>
|
||||||
{% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}>
|
|
||||||
<img class="empty-checkbox mr-3" />
|
<img class="empty-checkbox mr-3" />
|
||||||
</label>
|
</label>
|
||||||
<span class="label-area">{{ frappe.utils.md_to_html(option) }}</span>
|
<span class="label-area">{{ frappe.utils.md_to_html(option) }}</span>
|
||||||
@@ -51,6 +50,7 @@
|
|||||||
<button class="btn btn-primary pull-right" id="check" disabled>Check</button>
|
<button class="btn btn-primary pull-right" id="check" disabled>Check</button>
|
||||||
<button class="btn btn-primary hide" id="next">Next</button>
|
<button class="btn btn-primary hide" id="next">Next</button>
|
||||||
<button class="btn btn-primary hide" id="summary">Summary</button>
|
<button class="btn btn-primary hide" id="summary">Summary</button>
|
||||||
|
<small id="submission-message" class="font-weight-bold hide"> Please join the course to submit the Quiz.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="button is-secondary pull-right hide" id="try-again">Try Again</div>
|
<div class="button is-secondary pull-right hide" id="try-again">Try Again</div>
|
||||||
<h4 class="success-message"></h4>
|
<h4 class="success-message"></h4>
|
||||||
|
|||||||
@@ -40,14 +40,16 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% macro LessonContent(lesson) %}
|
{% macro LessonContent(lesson) %}
|
||||||
|
{% set is_instructor = frappe.session.user == course.instructor %}
|
||||||
<div class="lesson-content">
|
<div class="lesson-content">
|
||||||
<div class="course-home-headings title {% if membership %} is-member {% endif %}" data-lesson="{{ lesson.name }}"
|
<div class="course-home-headings title
|
||||||
|
{% if membership %} is-member {% endif %}
|
||||||
|
{% if membership or is_instructor %} eligible-for-submission {% endif %}" data-lesson="{{ lesson.name }}"
|
||||||
data-course="{{ course.name }}">
|
data-course="{{ course.name }}">
|
||||||
{{ lesson.title }}
|
{{ lesson.title }}
|
||||||
<span class="lesson-progress {{hide if course.get_progress(lesson.name) != 'Complete' else ''}}">COMPLETED</span>
|
<span class="lesson-progress {{hide if course.get_progress(lesson.name) != 'Complete' else ''}}">COMPLETED</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% set is_instructor = frappe.session.user == course.instructor %}
|
|
||||||
|
|
||||||
{% if membership or lesson.include_in_preview or is_instructor %}
|
{% if membership or lesson.include_in_preview or is_instructor %}
|
||||||
<div class="common-card-style lesson-content-card markdown-source">{{ lesson.render_html() }}</div>
|
<div class="common-card-style lesson-content-card markdown-source">{{ lesson.render_html() }}</div>
|
||||||
|
|||||||
@@ -133,7 +133,18 @@ var check_answer = (e) => {
|
|||||||
|
|
||||||
$(".explanation").removeClass("hide");
|
$(".explanation").removeClass("hide");
|
||||||
$("#check").addClass("hide");
|
$("#check").addClass("hide");
|
||||||
current_index == total_questions ? $("#summary").removeClass("hide") : $("#next").removeClass("hide");
|
|
||||||
|
if (current_index == total_questions) {
|
||||||
|
if ($(".eligible-for-submission").length) {
|
||||||
|
$("#summary").removeClass("hide")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#submission-message").removeClass("hide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#next").removeClass("hide")
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
|
|
||||||
if ($(document).width() <= 550) {
|
|
||||||
$(".certificate-footer").css("flex-direction", "column");
|
|
||||||
$(".certificate-footer").children().addClass("mb-5");
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#export-as-pdf").click((e) => {
|
$("#export-as-pdf").click((e) => {
|
||||||
export_as_pdf(e);
|
export_as_pdf(e);
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
var export_as_pdf = (e) => {
|
var export_as_pdf = (e) => {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro AboutOverviewSection(member) %}
|
{% macro AboutOverviewSection(member) %}
|
||||||
|
{% set enrollment = member.get_course_membership("Student") | length %}
|
||||||
|
{% set mentorship = member.get_course_membership("Mentor") | length %}
|
||||||
|
{% set reviews = member.get_user_reviews() | length %}
|
||||||
<div class="profile-parent-section">
|
<div class="profile-parent-section">
|
||||||
{% if member.bio %}
|
{% if member.bio %}
|
||||||
<div class="profile-about-section">
|
<div class="profile-about-section">
|
||||||
@@ -70,31 +73,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enrollment or reviews or mentorship %}
|
||||||
<div class="course-overview-section">
|
<div class="course-overview-section">
|
||||||
<div class="course-home-headings">
|
<div class="course-home-headings">
|
||||||
Overview
|
Overview
|
||||||
</div>
|
</div>
|
||||||
<div class="common-card-style overview-card small-title">
|
<div class="common-card-style overview-card small-title">
|
||||||
{% if member.get_course_membership("Student") | length %}
|
{% if enrollment %}
|
||||||
<div class="overtime-item">
|
<div class="overtime-item">
|
||||||
<img class="icon-background mr-1" src="/assets/community/icons/user.svg" />
|
<img class="icon-background mr-1" src="/assets/community/icons/user.svg" />
|
||||||
{{ member.get_course_membership("Student") | length }} Enrolled
|
{{ enrollment }} Enrolled
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if member.get_user_reviews() | length %}
|
{% if reviews %}
|
||||||
<div class="overtime-item">
|
<div class="overtime-item">
|
||||||
<img class="icon-background mr-1" src="/assets/community/icons/rating.svg" />
|
<img class="icon-background mr-1" src="/assets/community/icons/rating.svg" />
|
||||||
{{ member.get_user_reviews() | length }} Created
|
{{ reviews }} Created
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if member.get_course_membership("Mentor") | length%}
|
{% if mentorship %}
|
||||||
<div class="overtime-item">
|
<div class="overtime-item">
|
||||||
<img class="icon-background mr-1" src="/assets/community/icons/calendar.svg" />
|
<img class="icon-background mr-1" src="/assets/community/icons/calendar.svg" />
|
||||||
{{ member.get_course_membership("Mentor") | length }} Mentored
|
{{ mentorship }} Mentored
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user