mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 08:24:47 +00:00
chore: remove files related to LMS
This commit is contained in:
@@ -1,246 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}{{ content.name or 'Content Page' }}{% endblock %}
|
||||
|
||||
{% block head_include %}
|
||||
<style>
|
||||
.lms-content {
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
.lms-content h1 {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.lms-content h2 {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.lms-content h3 {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
||||
.lms-content h4 {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
.plyr--video .plyr__control.plyr__tab-focus,
|
||||
.plyr--video .plyr__control:hover,
|
||||
.plyr--video .plyr__control[aria-expanded='true'] {
|
||||
background: #5e64ff !important;
|
||||
}
|
||||
|
||||
.plyr__control--overlaid:focus,
|
||||
.plyr__control--overlaid:hover {
|
||||
background: #5e64ff !important;
|
||||
}
|
||||
|
||||
.plyr__menu__container .plyr__control[role=menuitemradio][aria-checked=true]::before {
|
||||
background: #5e64ff !important;
|
||||
}
|
||||
|
||||
.plyr__menu__container
|
||||
.plyr__control[role='menuitemradio'][aria-checked='true']::before {
|
||||
background: #5e64ff;
|
||||
}
|
||||
.plyr--full-ui input[type='range'] {
|
||||
color: #5e64ff !important;
|
||||
}
|
||||
|
||||
.plyr__control--overlaid {
|
||||
background: rgba(94, 100, 255, 0.8) !important;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.5.3/plyr.css" />
|
||||
{% endblock %}
|
||||
|
||||
{% macro title() %}
|
||||
<div class="mb-3">
|
||||
<a href="/lms/course?name={{ course }}&program={{ program }}" class="text-muted">
|
||||
{{_('Back to Course')}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="lms-title">
|
||||
<h2>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h2>
|
||||
<div class="lms-timer float-right fond-weight-bold hide"></div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro navigation() %}
|
||||
{% if previous %}
|
||||
<a href="/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ previous.content_type }}&content={{ previous.content }}" class='btn text-muted' style="box-shadow: none;">{{_('Previous')}}</a>
|
||||
{% else %}
|
||||
<a href="/lms/course?name={{ course }}&program={{ program }}" class='btn text-muted' style="box-shadow: none;">{{ _('Back to Course') }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if next %}
|
||||
<button id="nextButton" onclick="handle('/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ next.content_type }}&content={{ next.content }}')" class='btn btn-primary' disabled="true">{{_('Next')}}</button>
|
||||
{% else %}
|
||||
<button id="nextButton" onclick="handle('/lms/course?name={{ course }}&program={{ program }}')" class='btn btn-primary' disabled="true">{{_('Finish Topic')}}</button>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro video() %}
|
||||
<div class="mb-5">
|
||||
{{ title() }}
|
||||
<div class="text-muted">
|
||||
{% if content.duration %}
|
||||
{{ content.duration }} {{_('Mins')}}
|
||||
{% endif %}
|
||||
|
||||
{% if content.publish_date and content.duration%}
|
||||
-
|
||||
{% endif %}
|
||||
|
||||
{% if content.publish_date %}
|
||||
{{_('Published on')}} {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="player" data-plyr-provider="{{ content.provider|lower }}" data-plyr-embed-id="{{ content.url }}"></div>
|
||||
<div class="my-5 lms-content">
|
||||
{{ content.description }}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro article() %}
|
||||
<div class="mb-5">
|
||||
{{ title() }}
|
||||
<div class="text-muted">
|
||||
{% if content.author or content.publish_date %}
|
||||
{{_('Published')}}
|
||||
{% endif %}
|
||||
{% if content.author %}
|
||||
{{_('by')}} {{ content.author }}
|
||||
{% endif %}
|
||||
{% if content.publish_date %}
|
||||
{{_('on')}} {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="lms-content">
|
||||
{{ content.content }}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro quiz() %}
|
||||
<div class="mb-5">
|
||||
{{ title() }}
|
||||
</div>
|
||||
<div id="quiz-wrapper">
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div>
|
||||
<div class='container pb-5'>
|
||||
{% if content_type=='Video' %}
|
||||
{{ video() }}
|
||||
{% elif content_type=='Article'%}
|
||||
{{ article() }}
|
||||
{% elif content_type=='Quiz' %}
|
||||
{{ quiz() }}
|
||||
{% endif %}
|
||||
<div class="pull-right" {{ 'hidden' if content_type=='Quiz'}}>
|
||||
{{ navigation() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{% if content_type=='Video' %}
|
||||
<script src="https://cdn.plyr.io/3.5.3/plyr.js"></script>
|
||||
{% elif content_type == 'Quiz' %}
|
||||
<script src='/assets/erpnext/js/education/lms/quiz.js'></script>
|
||||
{% endif %}
|
||||
<script>
|
||||
{% if content_type == 'Video' %}
|
||||
const player = new Plyr('#player');
|
||||
{% elif content_type == 'Quiz' %}
|
||||
{% if next %}
|
||||
const quiz_exit_button = 'Next'
|
||||
const next_url = '/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ next.content_type }}&content={{ next.content }}'
|
||||
{% else %}
|
||||
const quiz_exit_button = 'Finish Course'
|
||||
const next_url = '/lms/course?name={{ course }}&program={{ program }}'
|
||||
{% endif %}
|
||||
frappe.ready(() => {
|
||||
{% if content.is_time_bound %}
|
||||
var duration = get_duration("{{content.duration}}")
|
||||
var d = frappe.msgprint({
|
||||
title: __('Important Notice'),
|
||||
indicator: "red",
|
||||
message: __(`This is a Time-Bound Quiz. <br><br>
|
||||
A timer for <b>${duration}</b> will start, once you click on <b>Proceed</b>. <br><br>
|
||||
If you fail to submit before the time is up, the Quiz will be submitted automatically.`),
|
||||
primary_action: {
|
||||
label: __("Proceed"),
|
||||
action: () => {
|
||||
create_quiz();
|
||||
d.hide();
|
||||
}
|
||||
},
|
||||
secondary_action: {
|
||||
action: () => {
|
||||
d.hide();
|
||||
window.location.href = "/lms/course?name={{ course }}&program={{ program }}";
|
||||
},
|
||||
label: __("Go Back"),
|
||||
}
|
||||
});
|
||||
{% else %}
|
||||
create_quiz();
|
||||
{% endif %}
|
||||
function create_quiz() {
|
||||
const quiz = new Quiz(document.getElementById('quiz-wrapper'), {
|
||||
name: '{{ content.name }}',
|
||||
course: '{{ course }}',
|
||||
program: '{{ program }}',
|
||||
quiz_exit_button: quiz_exit_button,
|
||||
next_url: next_url
|
||||
})
|
||||
window.quiz = quiz;
|
||||
}
|
||||
function get_duration(seconds){
|
||||
var hours = append_zero(Math.floor(seconds / 3600));
|
||||
var minutes = append_zero(Math.floor(seconds % 3600 / 60));
|
||||
var seconds = append_zero(Math.floor(seconds % 3600 % 60));
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
function append_zero(time) {
|
||||
return time > 9 ? time : "0" + time;
|
||||
}
|
||||
})
|
||||
{% endif %}
|
||||
|
||||
{% if content_type != 'Quiz' %}
|
||||
|
||||
frappe.ready(() => {
|
||||
next = document.getElementById('nextButton')
|
||||
next.disabled = false;
|
||||
})
|
||||
|
||||
|
||||
function handle(url) {
|
||||
opts = {
|
||||
method: "erpnext.education.utils.add_activity",
|
||||
args: {
|
||||
course: "{{ course }}",
|
||||
content_type: "{{ content_type }}",
|
||||
content: "{{ content.name }}",
|
||||
program: "{{ program }}"
|
||||
}
|
||||
}
|
||||
frappe.call(opts).then(res => {
|
||||
window.location.href = url;
|
||||
})
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,75 +0,0 @@
|
||||
import frappe
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
# Load Query Parameters
|
||||
try:
|
||||
program = frappe.form_dict["program"]
|
||||
content = frappe.form_dict["content"]
|
||||
content_type = frappe.form_dict["type"]
|
||||
course = frappe.form_dict["course"]
|
||||
topic = frappe.form_dict["topic"]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
# Check if user has access to the content
|
||||
has_program_access = utils.allowed_program_access(program)
|
||||
has_content_access = allowed_content_access(program, content, content_type)
|
||||
|
||||
if frappe.session.user == "Guest" or not has_program_access or not has_content_access:
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
# Set context for content to be displayer
|
||||
context.content = frappe.get_doc(content_type, content).as_dict()
|
||||
context.content_type = content_type
|
||||
context.program = program
|
||||
context.course = course
|
||||
context.topic = topic
|
||||
|
||||
topic = frappe.get_doc("Topic", topic)
|
||||
content_list = [
|
||||
{"content_type": item.content_type, "content": item.content} for item in topic.topic_content
|
||||
]
|
||||
|
||||
# Set context for progress numbers
|
||||
context.position = content_list.index({"content": content, "content_type": content_type})
|
||||
context.length = len(content_list)
|
||||
|
||||
# Set context for navigation
|
||||
context.previous = get_previous_content(content_list, context.position)
|
||||
context.next = get_next_content(content_list, context.position)
|
||||
|
||||
|
||||
def get_next_content(content_list, current_index):
|
||||
try:
|
||||
return content_list[current_index + 1]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
|
||||
def get_previous_content(content_list, current_index):
|
||||
if current_index == 0:
|
||||
return None
|
||||
else:
|
||||
return content_list[current_index - 1]
|
||||
|
||||
|
||||
def allowed_content_access(program, content, content_type):
|
||||
contents_of_program = frappe.db.sql(
|
||||
"""select `tabTopic Content`.content, `tabTopic Content`.content_type
|
||||
from `tabCourse Topic`,
|
||||
`tabProgram Course`,
|
||||
`tabTopic Content`
|
||||
where `tabCourse Topic`.parent = `tabProgram Course`.course
|
||||
and `tabTopic Content`.parent = `tabCourse Topic`.topic
|
||||
and `tabProgram Course`.parent = %(program)s""",
|
||||
{"program": program},
|
||||
)
|
||||
|
||||
return (content, content_type) in contents_of_program
|
||||
@@ -1,106 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}{{ course.course_name }}{% endblock %}
|
||||
{% from "www/lms/macros/hero.html" import hero %}
|
||||
{% from "www/lms/macros/card.html" import null_card %}
|
||||
|
||||
{% block head_include %}
|
||||
<style>
|
||||
div.card-hero-img {
|
||||
height: 220px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: rgb(250, 251, 252);
|
||||
}
|
||||
|
||||
.card-image-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 220px;
|
||||
background-color: rgb(250, 251, 252);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-body {
|
||||
align-self: center;
|
||||
color: #d1d8dd;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro card(topic) %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<div class="card h-100">
|
||||
{% if has_access %}
|
||||
<a href="/lms/topic?program={{ program }}&course={{ course.name }}&topic={{ topic.name }}" class="no-decoration no-underline">
|
||||
{% else %}
|
||||
<a href="/login#login">
|
||||
{% endif %}
|
||||
{% if topic.hero_image %}
|
||||
<div class="card-hero-img" style="background-image: url('{{ topic.hero_image }}')"></div>
|
||||
{% else %}
|
||||
<div class="card-image-wrapper text-center">
|
||||
<div class="image-body"><i class="fa fa-picture-o" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ topic.topic_name }}</h5>
|
||||
<div>
|
||||
<ol class="list-unstyled">
|
||||
{% for content in topic.topic_content %}
|
||||
<li>
|
||||
{% if has_access %}
|
||||
<a class="text-muted" href="/lms/content?program={{ program }}&course={{ course.name }}&topic={{ topic.name }}&type={{ content.content_type }}&content={{ content.content }}">
|
||||
{{ content.content }}
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="text-muted">{{ content.content }}</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
{% if has_access %}
|
||||
<div class='card-footer'>
|
||||
{% if progress[topic.name].completed %}
|
||||
<span class="indicator green">{{_('Completed')}}</span>
|
||||
{% elif progress[topic.name].started %}
|
||||
<span class="indicator orange">{{_('In Progress')}}</span>
|
||||
{% else %}
|
||||
<span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% else %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
{{ hero(course.course_name, course.description, has_access, {'name': 'Program', 'url': '/lms/program?program=' + program }) }}
|
||||
<div class='container'>
|
||||
<div class="row mt-5">
|
||||
{% for topic in topics %}
|
||||
{{ card(topic) }}
|
||||
{% endfor %}
|
||||
{% if topics %}
|
||||
{% for n in range( (3 - (topics|length)) %3) %}
|
||||
{{ null_card() }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,28 +0,0 @@
|
||||
import frappe
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
try:
|
||||
program = frappe.form_dict["program"]
|
||||
course_name = frappe.form_dict["name"]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
context.education_settings = frappe.get_single("Education Settings")
|
||||
course = frappe.get_doc("Course", course_name)
|
||||
context.program = program
|
||||
context.course = course
|
||||
|
||||
context.topics = course.get_topics()
|
||||
context.has_access = utils.allowed_program_access(context.program)
|
||||
context.progress = get_topic_progress(context.topics, course, context.program)
|
||||
|
||||
|
||||
def get_topic_progress(topics, course, program):
|
||||
progress = {topic.name: utils.get_topic_progress(topic, course.name, program) for topic in topics}
|
||||
return progress
|
||||
@@ -1,69 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}{{ education_settings.portal_title }}{% endblock %}
|
||||
{% from "www/lms/macros/card.html" import program_card %}
|
||||
{% from "www/lms/macros/card.html" import null_card %}
|
||||
|
||||
{% block head_include %}
|
||||
<meta name="description" content="{{ education_settings.description }}" />
|
||||
<meta name="keywords" content="ERP Software, Cloud ERP, Open Source ERP, Accounting Software, Online ERP, Online Accounting, ERP for small business" />
|
||||
<style>
|
||||
div.card-hero-img {
|
||||
height: 220px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: rgb(250, 251, 252);
|
||||
}
|
||||
|
||||
.card-image-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 220px;
|
||||
background-color: rgb(250, 251, 252);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-body {
|
||||
align-self: center;
|
||||
color: #d1d8dd;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="top-section" style="padding: 6rem 0rem;">
|
||||
<div class='container pb-5'>
|
||||
<h1>{{ education_settings.portal_title }}</h1>
|
||||
{% if education_settings.description %}
|
||||
<p class='lead'>{{ education_settings.description }}</p>
|
||||
{% endif %}
|
||||
<p class="mt-4">
|
||||
{% if frappe.session.user == 'Guest' %}
|
||||
<a class="btn btn-primary btn-lg" href="/login#signup">{{_('Sign Up')}}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class='container'>
|
||||
<div class="row mt-5">
|
||||
{% if featured_programs %}
|
||||
{% for program in featured_programs %}
|
||||
{{ program_card(program.program, program.has_access) }}
|
||||
{% endfor %}
|
||||
{% for n in range( (3 - (featured_programs|length)) %3) %}
|
||||
{{ null_card() }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="lead">You have not enrolled in any program. Contact your Instructor.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,17 +0,0 @@
|
||||
import frappe
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.education_settings = frappe.get_single("Education Settings")
|
||||
if not context.education_settings.enable_lms:
|
||||
frappe.local.flags.redirect_location = "/"
|
||||
raise frappe.Redirect
|
||||
context.featured_programs = get_featured_programs()
|
||||
|
||||
|
||||
def get_featured_programs():
|
||||
return utils.get_portal_programs() or []
|
||||
@@ -1,34 +0,0 @@
|
||||
{% macro program_card(program, has_access) %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<a href="/lms/program?program={{ program.name }}" class="no-decoration no-underline">
|
||||
<div class="card h-100">
|
||||
{% if program.hero_image %}
|
||||
<div class="card-hero-img" style="background-image: url('{{ program.hero_image }}')"></div>
|
||||
{% else %}
|
||||
<div class="card-image-wrapper text-center">
|
||||
<div class="image-body"><i class="fa fa-picture-o" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ program.program_name }}</h5>
|
||||
<div class="text-muted">{{ program.description[:110] + '...' if program.description else '' }}</div>
|
||||
</div>
|
||||
{% if has_access or program.intro_video%}
|
||||
<div class='card-footer'>
|
||||
{% if has_access %} <span class="indicator green">{{_('Enrolled')}}</span>
|
||||
{% elif program.intro_video %} <span><a href="{{ program.intro_video }}" target="blank">{{_('Watch Intro')}}</a></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro null_card() %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<div class="h-100 d-none d-sm-block" style="border: 1px solid rgba(209,216,221,0.5);border-radius: 0.25rem;background-color: rgb(250, 251, 252);">
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -1,53 +0,0 @@
|
||||
{% macro hero(title, description, has_access, back) %}
|
||||
<div class='container pb-5'>
|
||||
<div class="mb-3">
|
||||
<a href="{{ back.url }}" class="text-muted">
|
||||
{{_('Back to')}} {{ _(back.name) }}
|
||||
</a>
|
||||
</div>
|
||||
<h1>{{ title }}</h1>
|
||||
<p class='lead' style="max-width: 100%;">{{ description or ''}}</p>
|
||||
<p class="mt-4">
|
||||
{% if frappe.session.user == 'Guest' %}
|
||||
<a id="signup" class="btn btn-primary btn-lg" href="/login#signup">{{_('Sign Up')}}</a>
|
||||
{% elif not has_access %}
|
||||
<button id="enroll" class="btn btn-primary btn-lg" onclick="enroll()">{{_('Enroll')}}</button>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% block script %}
|
||||
<script type="text/javascript">
|
||||
frappe.ready(() => {
|
||||
btn = document.getElementById('enroll');
|
||||
})
|
||||
|
||||
function enroll() {
|
||||
let params = frappe.utils.get_query_params()
|
||||
|
||||
let btn = document.getElementById('enroll');
|
||||
|
||||
let opts = {
|
||||
method: 'erpnext.education.utils.enroll_in_program',
|
||||
args: {
|
||||
program_name: params.program
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __('Enrolling...')
|
||||
}
|
||||
|
||||
frappe.call(opts).then(res => {
|
||||
let success_dialog = new frappe.ui.Dialog({
|
||||
title: __('Success'),
|
||||
primary_action_label: __('OK'),
|
||||
primary_action: function() {
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
success_dialog.show();
|
||||
success_dialog.set_message(__('You have successfully enrolled for the program.'));
|
||||
})
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endmacro %}
|
||||
@@ -1,64 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}Profile{% endblock %}
|
||||
{% from "www/lms/macros/hero.html" import hero %}
|
||||
|
||||
{% block head_include %}
|
||||
<style>
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% macro card(program) %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<a href="/lms/program?program={{ program.name }}" class="no-decoration no-underline">
|
||||
<div class="card h-100">
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ program.program }}</h5>
|
||||
<ul class="list-unstyled text-muted">
|
||||
{% for course in program.progress %}
|
||||
<li>
|
||||
{% if course.completed %} <span class="indicator green">
|
||||
{% elif course.started %} <span class="indicator orange">
|
||||
{% else %} <span class="indicator blue">
|
||||
{% endif %}
|
||||
<a class="text-muted" href="/lms/course?name={{ course.name }}&program={{ program.name }}">{{ course.course }}</a>
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class='card-footer'>
|
||||
<span class="small">{{ program.completion }}{{_('% Complete')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class='container pb-5'>
|
||||
<div class="mb-3 row">
|
||||
<div class="col-md-7">
|
||||
<a href="/lms" class="text-muted">
|
||||
{{_('Back to Home')}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-5 text-right">
|
||||
<a href="/update-profile?name={{ frappe.session.user }}" target="blank" class="mt-0 text-muted">{{_('Edit Profile')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<h1>{{ student.first_name }} {{ student.last_name or '' }}</h1>
|
||||
<p class="lead" style="max-width: 100%;">{{ student.name }}</p>
|
||||
</div>
|
||||
<div class='container'>
|
||||
<div class="row mt-5">
|
||||
{% for program in progress %}
|
||||
{{ card(program) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,37 +0,0 @@
|
||||
import frappe
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
if frappe.session.user == "Guest":
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
context.student = utils.get_current_student()
|
||||
if not context.student:
|
||||
context.student = frappe.get_doc("User", frappe.session.user)
|
||||
context.progress = get_program_progress(context.student.name)
|
||||
|
||||
|
||||
def get_program_progress(student):
|
||||
enrolled_programs = frappe.get_all(
|
||||
"Program Enrollment", filters={"student": student}, fields=["program"]
|
||||
)
|
||||
student_progress = []
|
||||
for list_item in enrolled_programs:
|
||||
program = frappe.get_doc("Program", list_item.program)
|
||||
progress = utils.get_program_progress(program)
|
||||
completion = utils.get_program_completion(program)
|
||||
student_progress.append(
|
||||
{
|
||||
"program": program.program_name,
|
||||
"name": program.name,
|
||||
"progress": progress,
|
||||
"completion": completion,
|
||||
}
|
||||
)
|
||||
|
||||
return student_progress
|
||||
@@ -1,87 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}{{ program.program_name }}{% endblock %}
|
||||
{% from "www/lms/macros/hero.html" import hero %}
|
||||
{% from "www/lms/macros/card.html" import null_card %}
|
||||
|
||||
{% block head_include %}
|
||||
<style>
|
||||
div.card-hero-img {
|
||||
height: 220px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: rgb(250, 251, 252);
|
||||
}
|
||||
|
||||
.card-image-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 220px;
|
||||
background-color: rgb(250, 251, 252);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-body {
|
||||
align-self: center;
|
||||
color: #d1d8dd;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro card(course) %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<a href="/lms/course?name={{ course.name }}&program={{ program.name }}" class="no-decoration no-underline">
|
||||
<div class="card h-100">
|
||||
{% if course.hero_image %}
|
||||
<div class="card-hero-img" style="background-image: url('{{ course.hero_image }}')"></div>
|
||||
{% else %}
|
||||
<div class="card-image-wrapper text-center">
|
||||
<div class="image-body"><i class="fa fa-picture-o" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ course.course_name }}</h5>
|
||||
<div class="text-muted">{{ course.description[:110] + '...' if course.description else '' }}</div>
|
||||
</div>
|
||||
{% if has_access and progress[course.name] %}
|
||||
<div class='card-footer'>
|
||||
{% if progress[course.name].completed %}
|
||||
<span class="indicator green">{{_('Completed')}}</span>
|
||||
{% elif progress[course.name].started %}
|
||||
<span class="indicator orange">{{_('In Progress')}}</span>
|
||||
{% else %}
|
||||
<span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
{{ hero(program.program_name, program.description, has_access, {'name': 'Home', 'url': '/lms'}) }}
|
||||
<div class='container'>
|
||||
<div class="row mt-5">
|
||||
{% for course in courses %}
|
||||
{{ card(course) }}
|
||||
{% endfor %}
|
||||
{% if courses %}
|
||||
{% for n in range( (3 - (courses|length)) %3) %}
|
||||
{{ null_card() }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,32 +0,0 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
try:
|
||||
program = frappe.form_dict["program"]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
context.education_settings = frappe.get_single("Education Settings")
|
||||
context.program = get_program(program)
|
||||
context.courses = [frappe.get_doc("Course", course.course) for course in context.program.courses]
|
||||
context.has_access = utils.allowed_program_access(program)
|
||||
context.progress = get_course_progress(context.courses, context.program)
|
||||
|
||||
|
||||
def get_program(program_name):
|
||||
try:
|
||||
return frappe.get_doc("Program", program_name)
|
||||
except frappe.DoesNotExistError:
|
||||
frappe.throw(_("Program {0} does not exist.").format(program_name))
|
||||
|
||||
|
||||
def get_course_progress(courses, program):
|
||||
progress = {course.name: utils.get_course_progress(course, program) for course in courses}
|
||||
return progress or {}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}{{ topic.name }}{% endblock %}
|
||||
{% from "www/lms/macros/hero.html" import hero %}
|
||||
{% from "www/lms/macros/card.html" import null_card %}
|
||||
|
||||
{% block head_include %}
|
||||
<style>
|
||||
section {
|
||||
padding: 5rem 0 5rem 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro card(content, index, length) %}
|
||||
<div class="col-sm-4 mb-4 text-left">
|
||||
<a href="/lms/content?program={{ program }}&course={{ course }}&topic={{ topic.name }}&type={{ content.content_type }}&content={{ content.content.name }}" class="no-decoration no-underline">
|
||||
<div class="card h-100">
|
||||
<div class='card-body'>
|
||||
<div class="text-muted">{{ content.content_type or '' }}</div>
|
||||
<h5 class='card-title'>{{ content.content.name }}</h5>
|
||||
</div>
|
||||
{% if has_access %}
|
||||
<div class='card-footer'>
|
||||
{% if content.content_type == 'Quiz' %}
|
||||
{% if content.result == 'Fail' %} <span class="indicator red">{{_('Fail')}} <span class="text-muted">({{ content.score }}/100)</span></span>
|
||||
{% elif content.result == 'Pass' %} <span class="indicator green">{{_('Pass')}} <span class="text-muted">({{ content.score }}/100)</span>
|
||||
{% else %} <span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if content.completed %} <span class="indicator green">{{_('Completed')}}</span>
|
||||
{% else %} <span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
{{ hero(topic.topic_name, topic.description, has_access, {'name': 'Course', 'url': '/lms/course?name=' + course +'&program=' + program}) }}
|
||||
<div class='container'>
|
||||
<div class="row mt-5">
|
||||
{% for content in contents %}
|
||||
{{ card(content, loop.index, topic.contents|length) }}
|
||||
{% endfor %}
|
||||
{% if contents %}
|
||||
{% for n in range( (3 - (contents|length)) %3) %}
|
||||
{{ null_card() }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,57 +0,0 @@
|
||||
import frappe
|
||||
|
||||
import erpnext.education.utils as utils
|
||||
|
||||
no_cache = 1
|
||||
|
||||
|
||||
def get_context(context):
|
||||
try:
|
||||
course = frappe.form_dict["course"]
|
||||
program = frappe.form_dict["program"]
|
||||
topic = frappe.form_dict["topic"]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = "/lms"
|
||||
raise frappe.Redirect
|
||||
|
||||
context.program = program
|
||||
context.course = course
|
||||
context.topic = frappe.get_doc("Topic", topic)
|
||||
context.contents = get_contents(context.topic, course, program)
|
||||
context.has_access = utils.allowed_program_access(program)
|
||||
|
||||
|
||||
def get_contents(topic, course, program):
|
||||
student = utils.get_current_student()
|
||||
if student:
|
||||
course_enrollment = utils.get_or_create_course_enrollment(course, program)
|
||||
contents = topic.get_contents()
|
||||
progress = []
|
||||
if contents:
|
||||
for content in contents:
|
||||
if content.doctype in ("Article", "Video"):
|
||||
if student:
|
||||
status = utils.check_content_completion(content.name, content.doctype, course_enrollment.name)
|
||||
else:
|
||||
status = True
|
||||
progress.append({"content": content, "content_type": content.doctype, "completed": status})
|
||||
elif content.doctype == "Quiz":
|
||||
if student:
|
||||
status, score, result, time_taken = utils.check_quiz_completion(
|
||||
content, course_enrollment.name
|
||||
)
|
||||
else:
|
||||
status = False
|
||||
score = None
|
||||
result = None
|
||||
progress.append(
|
||||
{
|
||||
"content": content,
|
||||
"content_type": content.doctype,
|
||||
"completed": status,
|
||||
"score": score,
|
||||
"result": result,
|
||||
}
|
||||
)
|
||||
|
||||
return progress
|
||||
Reference in New Issue
Block a user