chore: remove files related to LMS
diff --git a/erpnext/domains/education.py b/erpnext/domains/education.py
deleted file mode 100644
index 23b8258..0000000
--- a/erpnext/domains/education.py
+++ /dev/null
@@ -1,19 +0,0 @@
-data = {
- "desktop_icons": [
- "Student",
- "Program",
- "Course",
- "Student Group",
- "Instructor",
- "Fees",
- "Task",
- "ToDo",
- "Education",
- "Student Attendance Tool",
- "Student Applicant",
- ],
- "default_portal_role": "Student",
- "restricted_roles": ["Student", "Instructor", "Academics User", "Education Manager"],
- "modules": ["Education"],
- "on_setup": "erpnext.education.setup.setup_education",
-}
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index fe0a89a..e178562 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -69,7 +69,6 @@
# website
update_website_context = [
"erpnext.e_commerce.shopping_cart.utils.update_website_context",
- "erpnext.education.doctype.education_settings.education_settings.update_website_context",
]
my_account_context = "erpnext.e_commerce.shopping_cart.utils.update_my_account_context"
webform_list_context = "erpnext.controllers.website_list_for_contact.get_webform_list_context"
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 29f1ce4..a97efff 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -11,10 +11,9 @@
from erpnext.controllers.employee_boarding_controller import update_employee_boarding_status
from erpnext.controllers.queries import get_filters_cond
-from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
-
+from erpnext import get_default_company
class Project(Document):
def get_feed(self):
@@ -665,3 +664,16 @@
project.status = status
project.save()
+
+def get_holiday_list(company=None):
+ if not company:
+ company = get_default_company() or frappe.get_all("Company")[0].name
+
+ holiday_list = frappe.get_cached_value("Company", company, "default_holiday_list")
+ if not holiday_list:
+ frappe.throw(
+ _("Please set a default Holiday List for Company {0}").format(
+ frappe.bold(get_default_company())
+ )
+ )
+ return holiday_list
\ No newline at end of file
diff --git a/erpnext/public/js/education/assessment_result_tool.html b/erpnext/public/js/education/assessment_result_tool.html
deleted file mode 100644
index f7d1ab3..0000000
--- a/erpnext/public/js/education/assessment_result_tool.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<table class="table table-bordered assessment-result-tool">
- <thead>
- <tr>
- <th style="width: 90px" rowspan="2">Student</th>
- <th style="width: 170px" rowspan="2">Student Name</th>
- {% for c in criteria %}
- <th class="score" style="width: 100px">{{ c.assessment_criteria }}</th>
- {% endfor %}
- <th class="score" style="width: 170px" rowspan="2">Comments</th>
- <th class="score" style="width: 100px">Total Marks</th>
- <!--criteria-->
- </tr>
- <tr>
- {% for c in criteria %}
- <th class="score" style="width: 100px">Score ({{ c.maximum_score }})</th>
- {% endfor %}
- <th class="score" style="width: 100px">Score ({{max_total_score}})</th>
- </tr>
- </thead>
- <tbody>
- {% for s in students %}
- <tr
- {% if(s.assessment_details && s.docstatus && s.docstatus == 1) { %} class="text-muted" {% } %}
- data-student="{{s.student}}">
-
- <td>{{ s.student }}</td>
- <td>{{ s.student_name }}</td>
- {% for c in criteria %}
- <td>
- <span data-student="{{s.student}}" data-criteria="{{c.assessment_criteria}}" class="student-result-grade badge" >
- {% if(s.assessment_details) { %}
- {{s.assessment_details[c.assessment_criteria][1]}}
- {% } %}
- </span>
- <input type="number" class="student-result-data" style="width:70%; float:right;"
- data-max-score="{{c.maximum_score}}"
- data-criteria="{{c.assessment_criteria}}"
- data-student="{{s.student}}"
- {% if(s.assessment_details && s.docstatus && s.docstatus == 1) { %} disabled {% } %}
- {% if(s.assessment_details) { %}
- value="{{s.assessment_details[c.assessment_criteria][0]}}"
- {% } %}/>
- </td>
- {% endfor %}
- <td>
- <input type="text" class="result-comment" data-student="{{s.student}}"
- {% if(s.assessment_details && s.docstatus && s.docstatus == 1) { %} disabled {% } %}
- {% if(s.assessment_details) { %}
- value="{{s.assessment_details.comment}}"
- {% } %}
- </td>
- <td>
- <span data-student="{{s.student}}" class="total-score-grade badge" style="width:30%; float:left;">
- {% if(s.assessment_details) { %}
- {{s.assessment_details.total_score[1]}}
- {% } %}
- </span>
- <span data-student="{{s.student}}" class="total-score" style="width:60%; float:center;">
- {% if(s.assessment_details) { %}
- {{s.assessment_details.total_score[0]}}
- {% } %}
- </span>
- <span data-student="{{s.student}}" class="total-result-link" style="width: 10%; display:{% if(!s.assessment_details) { %}None{% } %}; float:right;">
- <a class="btn-open no-decoration" title="Open Link" href="/app/Form/Assessment Result/{% if(s.assessment_details) { %}{{s.name}}{% } %}">
- <i class="octicon octicon-arrow-right"></i>
- </a>
- </span>
- </td>
- </tr>
- {% endfor %}
- </tbody>
-</table>
diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js
deleted file mode 100644
index 66160a7..0000000
--- a/erpnext/public/js/education/lms/quiz.js
+++ /dev/null
@@ -1,238 +0,0 @@
-class Quiz {
- constructor(wrapper, options) {
- this.wrapper = wrapper;
- Object.assign(this, options);
- this.questions = []
- this.refresh();
- }
-
- refresh() {
- this.get_quiz();
- }
-
- get_quiz() {
- frappe.call('erpnext.education.utils.get_quiz', {
- quiz_name: this.name,
- course: this.course
- }).then(res => {
- this.make(res.message)
- });
- }
-
- make(data) {
- if (data.is_time_bound) {
- $(".lms-timer").removeClass("hide");
- if (!data.activity || (data.activity && !data.activity.is_complete)) {
- this.initialiseTimer(data.duration);
- this.is_time_bound = true;
- this.time_taken = 0;
- }
- }
- data.questions.forEach(question_data => {
- let question_wrapper = document.createElement('div');
- let question = new Question({
- wrapper: question_wrapper,
- ...question_data
- });
- this.questions.push(question)
- this.wrapper.appendChild(question_wrapper);
- })
- if (data.activity && data.activity.is_complete) {
- this.disable()
- let indicator = 'red'
- let message = 'Your are not allowed to attempt the quiz again.'
- if (data.activity.result == 'Pass') {
- indicator = 'green'
- message = 'You have already cleared the quiz.'
- }
- if (data.activity.time_taken) {
- this.calculate_and_display_time(data.activity.time_taken, "Time Taken - ");
- }
- this.set_quiz_footer(message, indicator, data.activity.score)
- }
- else {
- this.make_actions();
- }
- window.addEventListener('beforeunload', (event) => {
- event.preventDefault();
- event.returnValue = '';
- });
- }
-
- initialiseTimer(duration) {
- this.time_left = duration;
- var self = this;
- var old_diff;
- this.calculate_and_display_time(this.time_left, "Time Left - ");
- this.start_time = new Date().getTime();
- this.timer = setInterval(function () {
- var diff = (new Date().getTime() - self.start_time)/1000;
- var variation = old_diff ? diff - old_diff : diff;
- old_diff = diff;
- self.time_left -= variation;
- self.time_taken += variation;
- self.calculate_and_display_time(self.time_left, "Time Left - ");
- if (self.time_left <= 0) {
- clearInterval(self.timer);
- self.time_taken -= 1;
- self.submit();
- }
- }, 1000);
- }
-
- calculate_and_display_time(second, text) {
- var timer_display = document.getElementsByClassName("lms-timer")[0];
- var hours = this.append_zero(Math.floor(second / 3600));
- var minutes = this.append_zero(Math.floor(second % 3600 / 60));
- var seconds = this.append_zero(Math.ceil(second % 3600 % 60));
- timer_display.innerText = text + hours + ":" + minutes + ":" + seconds;
- }
-
- append_zero(time) {
- return time > 9 ? time : "0" + time;
- }
-
- make_actions() {
- const button = document.createElement("button");
- button.classList.add("btn", "btn-primary", "mt-5", "mr-2");
-
- button.id = 'submit-button';
- button.innerText = 'Submit';
- button.onclick = () => this.submit();
- this.submit_btn = button
- this.wrapper.appendChild(button);
- }
-
- submit() {
- if (this.is_time_bound) {
- clearInterval(this.timer);
- $(".lms-timer").text("");
- }
- this.submit_btn.innerText = 'Evaluating..'
- this.submit_btn.disabled = true
- this.disable()
- frappe.call('erpnext.education.utils.evaluate_quiz', {
- quiz_name: this.name,
- quiz_response: this.get_selected(),
- course: this.course,
- program: this.program,
- time_taken: this.is_time_bound ? this.time_taken : 0
- }).then(res => {
- this.submit_btn.remove()
- if (!res.message) {
- frappe.throw(__("Something went wrong while evaluating the quiz."))
- }
-
- let indicator = 'red'
- let message = 'Fail'
- if (res.message.status == 'Pass') {
- indicator = 'green'
- message = 'Congratulations, you cleared the quiz.'
- }
-
- this.set_quiz_footer(message, indicator, res.message.score)
- });
- }
-
- set_quiz_footer(message, indicator, score) {
- const div = document.createElement("div");
- div.classList.add("mt-5");
- div.innerHTML = `<div class="row">
- <div class="col-md-8">
- <h4>${message}</h4>
- <h5 class="text-muted"><span class="indicator ${indicator}">Score: ${score}/100</span></h5>
- </div>
- <div class="col-md-4">
- <a href="${this.next_url}" class="btn btn-primary pull-right">${this.quiz_exit_button}</a>
- </div>
- </div>`
-
- this.wrapper.appendChild(div)
- }
-
- disable() {
- this.questions.forEach(que => que.disable())
- }
-
- get_selected() {
- let que = {}
- this.questions.forEach(question => {
- que[question.name] = question.get_selected()
- })
- return que
- }
-}
-
-class Question {
- constructor(opts) {
- Object.assign(this, opts);
- this.make();
- }
-
- make() {
- this.make_question()
- this.make_options()
- }
-
- get_selected() {
- let selected = this.options.filter(opt => opt.input.checked)
- if (this.type == 'Single Correct Answer') {
- if (selected[0]) return selected[0].name
- }
- if (this.type == 'Multiple Correct Answer') {
- return selected.map(opt => opt.name)
- }
- return null
- }
-
- disable() {
- let selected = this.options.forEach(opt => opt.input.disabled = true)
- }
-
- make_question() {
- let question_wrapper = document.createElement('h5');
- question_wrapper.classList.add('mt-3');
- question_wrapper.innerHTML = this.question;
- this.wrapper.appendChild(question_wrapper);
- }
-
- make_options() {
- let make_input = (name, value) => {
- let input = document.createElement('input');
- input.id = name;
- input.name = this.name;
- input.value = value;
- input.type = 'radio';
- if (this.type == 'Multiple Correct Answer')
- input.type = 'checkbox';
- input.classList.add('form-check-input');
- return input;
- }
-
- let make_label = function (name, value) {
- let label = document.createElement('label');
- label.classList.add('form-check-label');
- label.htmlFor = name;
- label.innerText = value;
- return label
- }
-
- let make_option = function (wrapper, option) {
- let option_div = document.createElement('div');
- option_div.classList.add('form-check', 'pb-1');
- let input = make_input(option.name, option.option);
- let label = make_label(option.name, option.option);
- option_div.appendChild(input);
- option_div.appendChild(label);
- wrapper.appendChild(option_div);
- return { input: input, ...option };
- }
-
- let options_wrapper = document.createElement('div')
- options_wrapper.classList.add('ml-2')
- let option_list = []
- this.options.forEach(opt => option_list.push(make_option(options_wrapper, opt)))
- this.options = option_list
- this.wrapper.appendChild(options_wrapper)
- }
-}
diff --git a/erpnext/www/lms/__init__.py b/erpnext/www/lms/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/www/lms/__init__.py
+++ /dev/null
diff --git a/erpnext/www/lms/content.html b/erpnext/www/lms/content.html
deleted file mode 100644
index d22ef66..0000000
--- a/erpnext/www/lms/content.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/content.py b/erpnext/www/lms/content.py
deleted file mode 100644
index 99462ce..0000000
--- a/erpnext/www/lms/content.py
+++ /dev/null
@@ -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
diff --git a/erpnext/www/lms/course.html b/erpnext/www/lms/course.html
deleted file mode 100644
index c07b940..0000000
--- a/erpnext/www/lms/course.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/course.py b/erpnext/www/lms/course.py
deleted file mode 100644
index 840beee..0000000
--- a/erpnext/www/lms/course.py
+++ /dev/null
@@ -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
diff --git a/erpnext/www/lms/index.html b/erpnext/www/lms/index.html
deleted file mode 100644
index c1e9620..0000000
--- a/erpnext/www/lms/index.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/index.py b/erpnext/www/lms/index.py
deleted file mode 100644
index 782ac48..0000000
--- a/erpnext/www/lms/index.py
+++ /dev/null
@@ -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 []
diff --git a/erpnext/www/lms/macros/__init__.py b/erpnext/www/lms/macros/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/www/lms/macros/__init__.py
+++ /dev/null
diff --git a/erpnext/www/lms/macros/card.html b/erpnext/www/lms/macros/card.html
deleted file mode 100644
index 3cbdec6..0000000
--- a/erpnext/www/lms/macros/card.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/macros/hero.html b/erpnext/www/lms/macros/hero.html
deleted file mode 100644
index dd3c23a..0000000
--- a/erpnext/www/lms/macros/hero.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/profile.html b/erpnext/www/lms/profile.html
deleted file mode 100644
index 5755dfe..0000000
--- a/erpnext/www/lms/profile.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/profile.py b/erpnext/www/lms/profile.py
deleted file mode 100644
index c4c1cd7..0000000
--- a/erpnext/www/lms/profile.py
+++ /dev/null
@@ -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
diff --git a/erpnext/www/lms/program.html b/erpnext/www/lms/program.html
deleted file mode 100644
index 30528c6..0000000
--- a/erpnext/www/lms/program.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/program.py b/erpnext/www/lms/program.py
deleted file mode 100644
index 1df2aa5..0000000
--- a/erpnext/www/lms/program.py
+++ /dev/null
@@ -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 {}
diff --git a/erpnext/www/lms/topic.html b/erpnext/www/lms/topic.html
deleted file mode 100644
index dc69599..0000000
--- a/erpnext/www/lms/topic.html
+++ /dev/null
@@ -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 %}
diff --git a/erpnext/www/lms/topic.py b/erpnext/www/lms/topic.py
deleted file mode 100644
index 7783211..0000000
--- a/erpnext/www/lms/topic.py
+++ /dev/null
@@ -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