refactor: renamed app to lms
This commit is contained in:
0
lms/lms/__init__.py
Normal file
0
lms/lms/__init__.py
Normal file
163
lms/lms/api.py
Normal file
163
lms/lms/api.py
Normal file
@@ -0,0 +1,163 @@
|
||||
"""API methods for the LMS.
|
||||
"""
|
||||
|
||||
import frappe
|
||||
|
||||
@frappe.whitelist()
|
||||
def autosave_section(section, code):
|
||||
"""Saves the code edited in one of the sections.
|
||||
"""
|
||||
doc = frappe.get_doc(
|
||||
doctype="Code Revision",
|
||||
section=section,
|
||||
code=code,
|
||||
author=frappe.session.user)
|
||||
doc.insert()
|
||||
return {"name": doc.name}
|
||||
|
||||
@frappe.whitelist()
|
||||
def submit_solution(exercise, code):
|
||||
"""Submits a solution.
|
||||
|
||||
@exerecise: name of the exercise to submit
|
||||
@code: solution to the exercise
|
||||
"""
|
||||
ex = frappe.get_doc("Exercise", exercise)
|
||||
if not ex:
|
||||
return
|
||||
doc = ex.submit(code)
|
||||
return {"name": doc.name, "creation": doc.creation}
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_current_lesson(course_name, lesson_name):
|
||||
"""Saves the current lesson for a student/mentor.
|
||||
"""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={
|
||||
"course": course_name,
|
||||
"member": frappe.session.user
|
||||
},
|
||||
fieldname="name")
|
||||
if not name:
|
||||
return
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.current_lesson = lesson_name
|
||||
doc.save(ignore_permissions=True)
|
||||
return {"current_lesson": doc.current_lesson}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def join_cohort(course, cohort, subgroup, invite_code):
|
||||
"""Creates a Cohort Join Request for given user.
|
||||
"""
|
||||
course_doc = frappe.get_doc("LMS Course", course)
|
||||
cohort_doc = course_doc and course_doc.get_cohort(cohort)
|
||||
subgroup_doc = cohort_doc and cohort_doc.get_subgroup(subgroup)
|
||||
|
||||
if not subgroup_doc or subgroup_doc.invite_code != invite_code:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid join link"
|
||||
}
|
||||
|
||||
data = {
|
||||
"doctype": "Cohort Join Request",
|
||||
"cohort": cohort_doc.name,
|
||||
"subgroup": subgroup_doc.name,
|
||||
"email": frappe.session.user,
|
||||
"status": "Pending"
|
||||
}
|
||||
# Don't insert duplicate records
|
||||
if frappe.db.exists(data):
|
||||
return {"ok": True, "status": "record found"}
|
||||
else:
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
return {"ok": True, "status": "record created"}
|
||||
|
||||
@frappe.whitelist()
|
||||
def approve_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Accepted"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
|
||||
r.status = "Accepted"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
@frappe.whitelist()
|
||||
def reject_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
|
||||
r.status = "Rejected"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def undo_reject_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
# keeping Pending as well to consider the case of duplicate requests
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
|
||||
r.status = "Pending"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_mentor_to_subgroup(subgroup, email):
|
||||
try:
|
||||
sg = frappe.get_doc("Cohort Subgroup", subgroup)
|
||||
except frappe.DoesNotExistError:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": f"Invalid subgroup: {subgroup}"
|
||||
}
|
||||
|
||||
if not sg.get_cohort().is_admin(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
|
||||
try:
|
||||
user = frappe.get_doc("User", email)
|
||||
except frappe.DoesNotExistError:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": f"Invalid user: {email}"
|
||||
}
|
||||
|
||||
sg.add_mentor(email)
|
||||
return {"ok": True}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"based_on": "creation",
|
||||
"chart_name": "Course Enrollments",
|
||||
"chart_type": "Count",
|
||||
"creation": "2021-09-30 12:23:09.414853",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "LMS Batch Membership",
|
||||
"dynamic_filters_json": "[]",
|
||||
"filters_json": "[]",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2021-10-17 13:32:21.745498",
|
||||
"modified": "2021-10-21 17:31:06.997133",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Course Enrollments",
|
||||
"number_of_groups": 0,
|
||||
"owner": "basawaraj@erpnext.com",
|
||||
"source": "",
|
||||
"time_interval": "Daily",
|
||||
"timeseries": 1,
|
||||
"timespan": "Last Quarter",
|
||||
"type": "Line",
|
||||
"use_report_chart": 0,
|
||||
"value_based_on": "",
|
||||
"y_axis": []
|
||||
}
|
||||
0
lms/lms/doctype/__init__.py
Normal file
0
lms/lms/doctype/__init__.py
Normal file
0
lms/lms/doctype/certification/__init__.py
Normal file
0
lms/lms/doctype/certification/__init__.py
Normal file
8
lms/lms/doctype/certification/certification.js
Normal file
8
lms/lms/doctype/certification/certification.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Certification', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
74
lms/lms/doctype/certification/certification.json
Normal file
74
lms/lms/doctype/certification/certification.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "hash",
|
||||
"creation": "2021-12-07 12:20:37.143096",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"certification_name",
|
||||
"organization",
|
||||
"description",
|
||||
"column_break_4",
|
||||
"expire",
|
||||
"issue_date",
|
||||
"expiration_date"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "certification_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Certification Name",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "organization",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Organization",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "issue_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Issue Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: !doc.expire",
|
||||
"fieldname": "expiration_date",
|
||||
"fieldtype": "Data",
|
||||
"label": "Expiration Date"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "expire",
|
||||
"fieldtype": "Check",
|
||||
"label": "This certificate does no expire"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-21 10:05:43.377876",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Certification",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
8
lms/lms/doctype/certification/certification.py
Normal file
8
lms/lms/doctype/certification/certification.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Certification(Document):
|
||||
pass
|
||||
8
lms/lms/doctype/certification/test_certification.py
Normal file
8
lms/lms/doctype/certification/test_certification.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCertification(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/chapter_reference/__init__.py
Normal file
0
lms/lms/doctype/chapter_reference/__init__.py
Normal file
35
lms/lms/doctype/chapter_reference/chapter_reference.json
Normal file
35
lms/lms/doctype/chapter_reference/chapter_reference.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2021-07-27 16:25:02.903245",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"chapter"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "chapter",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Chapter",
|
||||
"options": "Course Chapter",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-15 09:39:41.937565",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Chapter Reference",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
8
lms/lms/doctype/chapter_reference/chapter_reference.py
Normal file
8
lms/lms/doctype/chapter_reference/chapter_reference.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ChapterReference(Document):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort/__init__.py
Normal file
0
lms/lms/doctype/cohort/__init__.py
Normal file
8
lms/lms/doctype/cohort/cohort.js
Normal file
8
lms/lms/doctype/cohort/cohort.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
131
lms/lms/doctype/cohort/cohort.json
Normal file
131
lms/lms/doctype/cohort/cohort.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "format:{course}/{slug}",
|
||||
"creation": "2021-11-19 11:45:31.016097",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"course",
|
||||
"title",
|
||||
"slug",
|
||||
"section_break_2",
|
||||
"instructor",
|
||||
"status",
|
||||
"column_break_4",
|
||||
"begin_date",
|
||||
"end_date",
|
||||
"duration",
|
||||
"section_break_8",
|
||||
"description",
|
||||
"pages"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "instructor",
|
||||
"fieldtype": "Link",
|
||||
"label": "Instructor",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Upcoming\nLive\nCompleted\nCancelled",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "begin_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Begin Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "duration",
|
||||
"fieldtype": "Data",
|
||||
"label": "Duration"
|
||||
},
|
||||
{
|
||||
"fieldname": "slug",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Slug",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pages",
|
||||
"fieldtype": "Table",
|
||||
"label": "Pages",
|
||||
"options": "Cohort Web Page"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Links",
|
||||
"link_doctype": "Cohort Subgroup",
|
||||
"link_fieldname": "cohort"
|
||||
}
|
||||
],
|
||||
"modified": "2021-12-16 14:44:25.406301",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
85
lms/lms/doctype/cohort/cohort.py
Normal file
85
lms/lms/doctype/cohort/cohort.py
Normal file
@@ -0,0 +1,85 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Cohort(Document):
|
||||
def get_url(self):
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/cohorts/{self.slug}"
|
||||
|
||||
def get_subgroups(self, include_counts=False, sort_by=None):
|
||||
names = frappe.get_all("Cohort Subgroup", filters={"cohort": self.name}, pluck="name")
|
||||
subgroups = [frappe.get_cached_doc("Cohort Subgroup", name) for name in names]
|
||||
subgroups = sorted(subgroups, key=lambda sg: sg.title)
|
||||
|
||||
if include_counts:
|
||||
mentors = self._get_subgroup_counts("Cohort Mentor")
|
||||
students = self._get_subgroup_counts("LMS Batch Membership")
|
||||
join_requests = self._get_subgroup_counts("Cohort Join Request", status="Pending")
|
||||
for s in subgroups:
|
||||
s.num_mentors = mentors.get(s.name, 0)
|
||||
s.num_students = students.get(s.name, 0)
|
||||
s.num_join_requests = join_requests.get(s.name, 0)
|
||||
|
||||
if sort_by:
|
||||
subgroups.sort(key=lambda sg: getattr(sg, sort_by), reverse=True)
|
||||
return subgroups
|
||||
|
||||
def _get_subgroup_counts(self, doctype, **kw):
|
||||
rows = frappe.get_all(doctype,
|
||||
filters={"cohort": self.name, **kw},
|
||||
fields=['subgroup', 'count(*) as count'],
|
||||
group_by='subgroup')
|
||||
return {row['subgroup']: row['count'] for row in rows}
|
||||
|
||||
def _get_count(self, doctype, **kw):
|
||||
filters = {"cohort": self.name, **kw}
|
||||
return frappe.db.count(doctype, filters=filters)
|
||||
|
||||
def get_page_template(self, slug, scope=None):
|
||||
p = self.get_page(slug, scope=scope)
|
||||
return p and p.get_template_html()
|
||||
|
||||
def get_page(self, slug, scope=None):
|
||||
for p in self.pages:
|
||||
if p.slug == slug and scope in [p.scope, None]:
|
||||
return p
|
||||
|
||||
def get_pages(self, scope=None):
|
||||
return [p for p in self.pages if scope in [p.scope, None]]
|
||||
|
||||
def get_stats(self):
|
||||
return {
|
||||
"subgroups": self._get_count("Cohort Subgroup"),
|
||||
"mentors": self._get_count("Cohort Mentor"),
|
||||
"students": self._get_count("LMS Batch Membership"),
|
||||
"join_requests": self._get_count("Cohort Join Request", status="Pending"),
|
||||
}
|
||||
|
||||
def get_subgroup(self, slug):
|
||||
q = dict(cohort=self.name, slug=slug)
|
||||
name = frappe.db.get_value("Cohort Subgroup", q, "name")
|
||||
return name and frappe.get_doc("Cohort Subgroup", name)
|
||||
|
||||
def get_mentor(self, email):
|
||||
q = dict(cohort=self.name, email=email)
|
||||
name = frappe.db.get_value("Cohort Mentor", q, "name")
|
||||
return name and frappe.get_doc("Cohort Mentor", name)
|
||||
|
||||
def is_mentor(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"cohort": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def is_admin(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Staff",
|
||||
"cohort": self.name,
|
||||
"email": email,
|
||||
"role": "Admin"
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
8
lms/lms/doctype/cohort/test_cohort.py
Normal file
8
lms/lms/doctype/cohort/test_cohort.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCohort(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort_join_request/__init__.py
Normal file
0
lms/lms/doctype/cohort_join_request/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Join Request', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
76
lms/lms/doctype/cohort_join_request/cohort_join_request.json
Normal file
76
lms/lms/doctype/cohort_join_request/cohort_join_request.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-11-19 16:27:41.716509",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"cohort",
|
||||
"email",
|
||||
"column_break_3",
|
||||
"subgroup",
|
||||
"status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "cohort",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cohort",
|
||||
"options": "Cohort",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "subgroup",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Subgroup",
|
||||
"options": "Cohort Subgroup",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "E-Mail",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "Pending",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Pending\nAccepted\nRejected"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-16 15:06:03.985221",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort Join Request",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
51
lms/lms/doctype/cohort_join_request/cohort_join_request.py
Normal file
51
lms/lms/doctype/cohort_join_request/cohort_join_request.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CohortJoinRequest(Document):
|
||||
def on_update(self):
|
||||
if self.status == "Accepted":
|
||||
self.ensure_student()
|
||||
|
||||
def ensure_student(self):
|
||||
# case 1 - user is already a member
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student"
|
||||
}
|
||||
if frappe.db.exists(q):
|
||||
return
|
||||
|
||||
# case 2 - user has signed up for this course, possibly not this cohort
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"member": self.email,
|
||||
"member_type": "Student"
|
||||
}
|
||||
name = frappe.db.exists(q)
|
||||
if name:
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.cohort = self.cohort
|
||||
doc.subgroup = self.subgroup
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
# case 3 - user has not signed up for this course yet
|
||||
data = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student",
|
||||
"role": "Member"
|
||||
}
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCohortJoinRequest(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort_mentor/__init__.py
Normal file
0
lms/lms/doctype/cohort_mentor/__init__.py
Normal file
8
lms/lms/doctype/cohort_mentor/cohort_mentor.js
Normal file
8
lms/lms/doctype/cohort_mentor/cohort_mentor.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Mentor', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
73
lms/lms/doctype/cohort_mentor/cohort_mentor.json
Normal file
73
lms/lms/doctype/cohort_mentor/cohort_mentor.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-11-19 15:31:47.129156",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"cohort",
|
||||
"email",
|
||||
"subgroup",
|
||||
"course"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "cohort",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Cohort",
|
||||
"options": "Cohort",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "E-mail",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "subgroup",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Primary Subgroup",
|
||||
"options": "Cohort Subgroup",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "cohort.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-11-29 16:32:33.235281",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort Mentor",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
12
lms/lms/doctype/cohort_mentor/cohort_mentor.py
Normal file
12
lms/lms/doctype/cohort_mentor/cohort_mentor.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CohortMentor(Document):
|
||||
def get_subgroup(self):
|
||||
return frappe.get_doc("Cohort Subgroup", self.subgroup)
|
||||
|
||||
def get_user(self):
|
||||
return frappe.get_doc("User", self.email)
|
||||
8
lms/lms/doctype/cohort_mentor/test_cohort_mentor.py
Normal file
8
lms/lms/doctype/cohort_mentor/test_cohort_mentor.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCohortMentor(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort_staff/__init__.py
Normal file
0
lms/lms/doctype/cohort_staff/__init__.py
Normal file
8
lms/lms/doctype/cohort_staff/cohort_staff.js
Normal file
8
lms/lms/doctype/cohort_staff/cohort_staff.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Staff', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
77
lms/lms/doctype/cohort_staff/cohort_staff.json
Normal file
77
lms/lms/doctype/cohort_staff/cohort_staff.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-11-19 15:35:00.551949",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"cohort",
|
||||
"course",
|
||||
"column_break_3",
|
||||
"email",
|
||||
"role"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "cohort",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Cohort",
|
||||
"options": "Cohort",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "role",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Role",
|
||||
"options": "Admin\nManager\nStaff",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "cohort.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-16 15:16:04.042372",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort Staff",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
8
lms/lms/doctype/cohort_staff/cohort_staff.py
Normal file
8
lms/lms/doctype/cohort_staff/cohort_staff.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CohortStaff(Document):
|
||||
pass
|
||||
8
lms/lms/doctype/cohort_staff/test_cohort_staff.py
Normal file
8
lms/lms/doctype/cohort_staff/test_cohort_staff.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCohortStaff(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort_subgroup/__init__.py
Normal file
0
lms/lms/doctype/cohort_subgroup/__init__.py
Normal file
8
lms/lms/doctype/cohort_subgroup/cohort_subgroup.js
Normal file
8
lms/lms/doctype/cohort_subgroup/cohort_subgroup.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Subgroup', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
104
lms/lms/doctype/cohort_subgroup/cohort_subgroup.json
Normal file
104
lms/lms/doctype/cohort_subgroup/cohort_subgroup.json
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "format:{title} ({cohort})",
|
||||
"creation": "2021-11-19 11:50:27.312434",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"cohort",
|
||||
"slug",
|
||||
"title",
|
||||
"column_break_4",
|
||||
"invite_code",
|
||||
"course",
|
||||
"section_break_7",
|
||||
"description"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "cohort",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_preview": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Cohort",
|
||||
"options": "Cohort",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"in_preview": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "invite_code",
|
||||
"fieldtype": "Data",
|
||||
"label": "Invite Code",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "slug",
|
||||
"fieldtype": "Data",
|
||||
"label": "Slug",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "cohort.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Links",
|
||||
"link_doctype": "Cohort Join Request",
|
||||
"link_fieldname": "subgroup"
|
||||
}
|
||||
],
|
||||
"modified": "2021-12-16 15:12:42.504883",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort Subgroup",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
95
lms/lms/doctype/cohort_subgroup/cohort_subgroup.py
Normal file
95
lms/lms/doctype/cohort_subgroup/cohort_subgroup.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import random_string
|
||||
|
||||
class CohortSubgroup(Document):
|
||||
def before_save(self):
|
||||
if not self.invite_code:
|
||||
self.invite_code = random_string(8)
|
||||
|
||||
def get_url(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/subgroups/{cohort.slug}/{self.slug}"
|
||||
|
||||
def get_invite_link(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/join/{cohort.slug}/{self.slug}/{self.invite_code}"
|
||||
|
||||
def has_student(self, email):
|
||||
"""Check if given user is a student of this subgroup.
|
||||
"""
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"subgroup": self.name,
|
||||
"member": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def has_join_request(self, email):
|
||||
"""Check if given user is a student of this subgroup.
|
||||
"""
|
||||
q = {
|
||||
"doctype": "Cohort Join Request",
|
||||
"subgroup": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def get_join_requests(self, status="Pending"):
|
||||
q = {
|
||||
"subgroup": self.name,
|
||||
"status": status
|
||||
}
|
||||
return frappe.get_all("Cohort Join Request", filters=q, fields=["*"], order_by="creation desc")
|
||||
|
||||
def get_mentors(self):
|
||||
emails = frappe.get_all("Cohort Mentor", filters={"subgroup": self.name}, fields=["email"], pluck='email')
|
||||
return self._get_users(emails)
|
||||
|
||||
def get_students(self):
|
||||
emails = frappe.get_all("LMS Batch Membership",
|
||||
filters={"subgroup": self.name},
|
||||
fields=["member"],
|
||||
pluck='member',
|
||||
page_length=1000)
|
||||
return self._get_users(emails)
|
||||
|
||||
def _get_users(self, emails):
|
||||
users = [frappe.get_cached_doc("User", email) for email in emails]
|
||||
return sorted(users, key=lambda user: user.full_name)
|
||||
|
||||
def is_mentor(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"subgroup": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def is_manager(self, email):
|
||||
"""Returns True if the given user is a manager of this subgroup.
|
||||
|
||||
Mentors of the subgroup, admins of the Cohort are considered as managers.
|
||||
"""
|
||||
return self.is_mentor(email) or self.get_cohort().is_admin(email)
|
||||
|
||||
def get_cohort(self):
|
||||
return frappe.get_doc("Cohort", self.cohort)
|
||||
|
||||
def add_mentor(self, email):
|
||||
d = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"subgroup": self.name,
|
||||
"cohort": self.cohort,
|
||||
"email": email
|
||||
}
|
||||
if frappe.db.exists(d):
|
||||
return
|
||||
doc = frappe.get_doc(d)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
#def after_doctype_insert():
|
||||
# frappe.db.add_unique("Cohort Subgroup", ("cohort", "slug"))
|
||||
8
lms/lms/doctype/cohort_subgroup/test_cohort_subgroup.py
Normal file
8
lms/lms/doctype/cohort_subgroup/test_cohort_subgroup.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCohortSubgroup(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/cohort_web_page/__init__.py
Normal file
0
lms/lms/doctype/cohort_web_page/__init__.py
Normal file
64
lms/lms/doctype/cohort_web_page/cohort_web_page.json
Normal file
64
lms/lms/doctype/cohort_web_page/cohort_web_page.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-12-04 23:28:40.429867",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"slug",
|
||||
"title",
|
||||
"template",
|
||||
"scope",
|
||||
"required_role"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "template",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Template",
|
||||
"options": "Web Template",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "Cohort",
|
||||
"fieldname": "scope",
|
||||
"fieldtype": "Select",
|
||||
"label": "Scope",
|
||||
"options": "Cohort\nSubgroup"
|
||||
},
|
||||
{
|
||||
"default": "Public",
|
||||
"fieldname": "required_role",
|
||||
"fieldtype": "Select",
|
||||
"label": "Required Role",
|
||||
"options": "Public\nStudent\nMentor\nAdmin"
|
||||
},
|
||||
{
|
||||
"fieldname": "slug",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Slug",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-04 23:33:03.954128",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Cohort Web Page",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
9
lms/lms/doctype/cohort_web_page/cohort_web_page.py
Normal file
9
lms/lms/doctype/cohort_web_page/cohort_web_page.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CohortWebPage(Document):
|
||||
def get_template_html(self):
|
||||
return frappe.get_doc("Web Template", self.template).template
|
||||
0
lms/lms/doctype/course_chapter/__init__.py
Normal file
0
lms/lms/doctype/course_chapter/__init__.py
Normal file
14
lms/lms/doctype/course_chapter/course_chapter.js
Normal file
14
lms/lms/doctype/course_chapter/course_chapter.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Course Chapter', {
|
||||
onload: function (frm) {
|
||||
frm.set_query("lesson", "lessons", function () {
|
||||
return {
|
||||
filters: {
|
||||
"chapter": frm.doc.name,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
102
lms/lms/doctype/course_chapter/course_chapter.json
Normal file
102
lms/lms/doctype/course_chapter/course_chapter.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "format:{####} {title}",
|
||||
"creation": "2021-05-03 05:49:08.383058",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"course",
|
||||
"title",
|
||||
"column_break_3",
|
||||
"description",
|
||||
"section_break_5",
|
||||
"lessons"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "lessons",
|
||||
"fieldtype": "Table",
|
||||
"label": "Lessons",
|
||||
"options": "Lesson Reference"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Lessons",
|
||||
"link_doctype": "Course Lesson",
|
||||
"link_fieldname": "chapter"
|
||||
}
|
||||
],
|
||||
"modified": "2022-03-14 17:57:00.707416",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Course Chapter",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "title",
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
8
lms/lms/doctype/course_chapter/course_chapter.py
Normal file
8
lms/lms/doctype/course_chapter/course_chapter.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CourseChapter(Document):
|
||||
pass
|
||||
8
lms/lms/doctype/course_chapter/test_course_chapter.py
Normal file
8
lms/lms/doctype/course_chapter/test_course_chapter.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCourseChapter(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/course_instructor/__init__.py
Normal file
0
lms/lms/doctype/course_instructor/__init__.py
Normal file
32
lms/lms/doctype/course_instructor/course_instructor.json
Normal file
32
lms/lms/doctype/course_instructor/course_instructor.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2022-02-07 11:39:59.998762",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"instructor"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "instructor",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Instructor",
|
||||
"options": "User"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-02-07 11:41:42.943250",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Course Instructor",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
8
lms/lms/doctype/course_instructor/course_instructor.py
Normal file
8
lms/lms/doctype/course_instructor/course_instructor.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2022, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CourseInstructor(Document):
|
||||
pass
|
||||
0
lms/lms/doctype/course_lesson/__init__.py
Normal file
0
lms/lms/doctype/course_lesson/__init__.py
Normal file
104
lms/lms/doctype/course_lesson/course_lesson.js
Normal file
104
lms/lms/doctype/course_lesson/course_lesson.js
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Course Lesson', {
|
||||
setup: function (frm) {
|
||||
frm.trigger('setup_help');
|
||||
},
|
||||
setup_help(frm) {
|
||||
frm.get_field('help').html(`
|
||||
<p>You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same.</p>
|
||||
<div class="row font-weight-bold mb-3">
|
||||
<div class="col-sm-8">
|
||||
Content Type
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
Syntax
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
Video
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{{ Video("url_of_source") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
YouTube Video
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{{ YouTubeVideo("unique_embed_id") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
Exercise
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{{ Exercise("exercise_name") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
Quiz
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{{ Quiz("lms_quiz_name") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
Assignment
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{{ Assignment("id-filetype") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row font-weight-bold mb-3">
|
||||
<div class="col-sm-8">
|
||||
Supported File Types for Assignment
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
Syntax
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
.doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
Document
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
.pdf
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
PDF
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-8">
|
||||
.png, .jpg, .jpeg
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
Image
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
});
|
||||
124
lms/lms/doctype/course_lesson/course_lesson.json
Normal file
124
lms/lms/doctype/course_lesson/course_lesson.json
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_events_in_timeline": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "format:{####} {title}",
|
||||
"creation": "2021-05-03 06:21:12.995984",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"chapter",
|
||||
"course",
|
||||
"include_in_preview",
|
||||
"column_break_4",
|
||||
"title",
|
||||
"index_label",
|
||||
"section_break_6",
|
||||
"body",
|
||||
"help_section",
|
||||
"help"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "chapter",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Course Chapter",
|
||||
"options": "Course Chapter",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "include_in_preview",
|
||||
"fieldtype": "Check",
|
||||
"label": "Include In Preview"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "index_label",
|
||||
"fieldtype": "Data",
|
||||
"label": "Index Label",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "body",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"ignore_xss_filter": 1,
|
||||
"label": "Body",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "help_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Help"
|
||||
},
|
||||
{
|
||||
"fieldname": "help",
|
||||
"fieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"fetch_from": "chapter.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-14 18:56:31.969801",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Course Lesson",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
114
lms/lms/doctype/course_lesson/course_lesson.py
Normal file
114
lms/lms/doctype/course_lesson/course_lesson.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from ...md import find_macros
|
||||
from lms.lms.utils import get_course_progress, get_lesson_url
|
||||
|
||||
class CourseLesson(Document):
|
||||
def validate(self):
|
||||
self.check_and_create_folder()
|
||||
|
||||
def on_update(self):
|
||||
dynamic_documents = ["Exercise", "Quiz"]
|
||||
for section in dynamic_documents:
|
||||
self.update_lesson_name_in_document(section)
|
||||
|
||||
def update_lesson_name_in_document(self, section):
|
||||
doctype_map= {
|
||||
"Exercise": "Exercise",
|
||||
"Quiz": "LMS Quiz"
|
||||
}
|
||||
macros = find_macros(self.body)
|
||||
documents = [value for name, value in macros if name == section]
|
||||
index = 1
|
||||
for name in documents:
|
||||
e = frappe.get_doc(doctype_map[section], name)
|
||||
e.lesson = self.name
|
||||
e.index_ = index
|
||||
e.save()
|
||||
index += 1
|
||||
self.update_orphan_documents(doctype_map[section], documents)
|
||||
|
||||
def update_orphan_documents(self, doctype, documents):
|
||||
"""Updates the documents that were previously part of this lesson,
|
||||
but not any more.
|
||||
"""
|
||||
linked_documents = {row['name'] for row in frappe.get_all(doctype, {"lesson": self.name})}
|
||||
active_documents = set(documents)
|
||||
orphan_documents = linked_documents - active_documents
|
||||
for name in orphan_documents:
|
||||
ex = frappe.get_doc(doctype, name)
|
||||
ex.lesson = None
|
||||
ex.index_ = 0
|
||||
ex.index_label = ""
|
||||
ex.save()
|
||||
|
||||
def check_and_create_folder(self):
|
||||
course = frappe.db.get_value("Chapter", self.chapter, "course")
|
||||
args = {
|
||||
"doctype": "File",
|
||||
"is_folder": True,
|
||||
"file_name": f"{self.name} {course}"
|
||||
}
|
||||
if not frappe.db.exists(args):
|
||||
folder = frappe.get_doc(args)
|
||||
folder.save(ignore_permissions=True)
|
||||
|
||||
def get_exercises(self):
|
||||
if not self.body:
|
||||
return []
|
||||
|
||||
macros = find_macros(self.body)
|
||||
exercises = [value for name, value in macros if name == "Exercise"]
|
||||
return [frappe.get_doc("Exercise", name) for name in exercises]
|
||||
|
||||
def get_progress(self):
|
||||
return frappe.db.get_value("LMS Course Progress", {"lesson": self.name, "owner": frappe.session.user}, "status")
|
||||
|
||||
def get_slugified_class(self):
|
||||
if self.get_progress():
|
||||
return ("").join([ s for s in self.get_progress().lower().split() ])
|
||||
return
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_progress(lesson, course, status):
|
||||
membership = frappe.db.exists("LMS Batch Membership",
|
||||
{
|
||||
"member": frappe.session.user,
|
||||
"course": course
|
||||
})
|
||||
if not membership:
|
||||
return
|
||||
|
||||
if frappe.db.exists("LMS Course Progress",
|
||||
{
|
||||
"lesson": lesson,
|
||||
"owner": frappe.session.user,
|
||||
"course": course
|
||||
}):
|
||||
doc = frappe.get_doc("LMS Course Progress",
|
||||
{
|
||||
"lesson": lesson,
|
||||
"owner": frappe.session.user,
|
||||
"course": course
|
||||
})
|
||||
doc.status = status
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
frappe.get_doc({
|
||||
"doctype": "LMS Course Progress",
|
||||
"lesson": lesson,
|
||||
"status": status,
|
||||
}).save(ignore_permissions=True)
|
||||
|
||||
progress = get_course_progress(course)
|
||||
frappe.db.set_value("LMS Batch Membership", membership, "progress", progress)
|
||||
return progress
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_lesson_info(chapter):
|
||||
return frappe.db.get_value("Course Chapter", chapter, "course")
|
||||
8
lms/lms/doctype/course_lesson/test_course_lesson.py
Normal file
8
lms/lms/doctype/course_lesson/test_course_lesson.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestCourseLesson(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/education_detail/__init__.py
Normal file
0
lms/lms/doctype/education_detail/__init__.py
Normal file
87
lms/lms/doctype/education_detail/education_detail.json
Normal file
87
lms/lms/doctype/education_detail/education_detail.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "hash",
|
||||
"creation": "2021-12-07 12:15:46.078717",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"institution_name",
|
||||
"location",
|
||||
"degree_type",
|
||||
"major",
|
||||
"column_break_5",
|
||||
"grade_type",
|
||||
"grade",
|
||||
"start_date",
|
||||
"end_date"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "institution_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Institution Name",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "location",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Location",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "degree_type",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Degree Type",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "grade_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Grade Type",
|
||||
"options": "Percentage (e.g. 70%)\nPoint of Score (e.g. 70)\nLetter Grade (e.g. A, B-)\nUK Grading (e.g. 1st, 2:2)\nFrench (e.g. Distinction)\nCGPA/4"
|
||||
},
|
||||
{
|
||||
"fieldname": "grade",
|
||||
"fieldtype": "Data",
|
||||
"label": "Grade"
|
||||
},
|
||||
{
|
||||
"fieldname": "major",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Field of Major/Study",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Start Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date (or expected)"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-21 09:58:42.343823",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Education Detail",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
8
lms/lms/doctype/education_detail/education_detail.py
Normal file
8
lms/lms/doctype/education_detail/education_detail.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class EducationDetail(Document):
|
||||
pass
|
||||
0
lms/lms/doctype/exercise/__init__.py
Normal file
0
lms/lms/doctype/exercise/__init__.py
Normal file
8
lms/lms/doctype/exercise/exercise.js
Normal file
8
lms/lms/doctype/exercise/exercise.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
123
lms/lms/doctype/exercise/exercise.json
Normal file
123
lms/lms/doctype/exercise/exercise.json
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-05-19 17:43:39.923430",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"description",
|
||||
"code",
|
||||
"answer",
|
||||
"column_break_4",
|
||||
"course",
|
||||
"hints",
|
||||
"tests",
|
||||
"image",
|
||||
"lesson",
|
||||
"index_",
|
||||
"index_label"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title"
|
||||
},
|
||||
{
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course"
|
||||
},
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "answer",
|
||||
"fieldtype": "Code",
|
||||
"label": "Answer"
|
||||
},
|
||||
{
|
||||
"fieldname": "tests",
|
||||
"fieldtype": "Code",
|
||||
"label": "Tests"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "hints",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Hints"
|
||||
},
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "code",
|
||||
"fieldtype": "Code",
|
||||
"label": "Code"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Code",
|
||||
"label": "Image",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "lesson",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Lesson",
|
||||
"options": "Course Lesson"
|
||||
},
|
||||
{
|
||||
"fieldname": "index_",
|
||||
"fieldtype": "Int",
|
||||
"label": "Index",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "index_label",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Index Label",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-09-29 15:27:55.585874",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Exercise",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "title",
|
||||
"sort_field": "index_label",
|
||||
"sort_order": "ASC",
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
53
lms/lms/doctype/exercise/exercise.py
Normal file
53
lms/lms/doctype/exercise/exercise.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from lms.lms.utils import get_membership
|
||||
|
||||
class Exercise(Document):
|
||||
def get_user_submission(self):
|
||||
"""Returns the latest submission for this user.
|
||||
"""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
|
||||
result = frappe.get_all('Exercise Submission',
|
||||
fields="*",
|
||||
filters={
|
||||
"owner": user,
|
||||
"exercise": self.name
|
||||
},
|
||||
order_by="creation desc",
|
||||
page_length=1)
|
||||
|
||||
if result:
|
||||
return result[0]
|
||||
|
||||
def submit(self, code):
|
||||
"""Submits the given code as solution to exercise.
|
||||
"""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
|
||||
old_submission = self.get_user_submission()
|
||||
if old_submission and old_submission.solution == code:
|
||||
return old_submission
|
||||
|
||||
member = get_membership(self.course, frappe.session.user)
|
||||
|
||||
doc = frappe.get_doc(
|
||||
doctype="Exercise Submission",
|
||||
exercise=self.name,
|
||||
exercise_title=self.title,
|
||||
course=self.course,
|
||||
lesson=self.lesson,
|
||||
batch=member.batch,
|
||||
solution=code,
|
||||
member=member.name)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
return doc
|
||||
|
||||
56
lms/lms/doctype/exercise/test_exercise.py
Normal file
56
lms/lms/doctype/exercise/test_exercise.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestExercise(unittest.TestCase):
|
||||
def setUp(self):
|
||||
frappe.db.sql('delete from `tabLMS Batch Membership`')
|
||||
frappe.db.sql('delete from `tabExercise Submission`')
|
||||
frappe.db.sql('delete from `tabExercise`')
|
||||
frappe.db.sql('delete from `tabLMS Course`')
|
||||
|
||||
def new_exercise(self):
|
||||
course = frappe.get_doc({
|
||||
"doctype": "LMS Course",
|
||||
"name": "test-course",
|
||||
"title": "Test Course",
|
||||
"short_introduction": "Test Course",
|
||||
"description": "Test Course"
|
||||
})
|
||||
course.insert()
|
||||
member = frappe.get_doc({
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": course.name,
|
||||
"member": frappe.session.user
|
||||
})
|
||||
member.insert()
|
||||
e = frappe.get_doc({
|
||||
"doctype": "Exercise",
|
||||
"name": "test-problem",
|
||||
"course": course.name,
|
||||
"title": "Test Problem",
|
||||
"description": "draw a circle",
|
||||
"code": "# draw a single cicle",
|
||||
"answer": (
|
||||
"# draw a single circle\n" +
|
||||
"circle(100, 100, 50)")
|
||||
})
|
||||
e.insert()
|
||||
return e
|
||||
|
||||
def test_exercise(self):
|
||||
e = self.new_exercise()
|
||||
assert e.get_user_submission() is None
|
||||
|
||||
def test_exercise_submission(self):
|
||||
e = self.new_exercise()
|
||||
submission = e.submit("circle(100, 100, 50)")
|
||||
assert submission is not None
|
||||
assert submission.exercise == e.name
|
||||
assert submission.course == e.course
|
||||
|
||||
user_submission = e.get_user_submission()
|
||||
assert user_submission is not None
|
||||
assert user_submission.name == submission.name
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise Latest Submission', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-12-08 17:56:26.049675",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"exercise",
|
||||
"status",
|
||||
"batch",
|
||||
"column_break_4",
|
||||
"exercise_title",
|
||||
"course",
|
||||
"lesson",
|
||||
"section_break_8",
|
||||
"solution",
|
||||
"image",
|
||||
"test_results",
|
||||
"comments",
|
||||
"latest_submission",
|
||||
"member",
|
||||
"member_email",
|
||||
"member_cohort",
|
||||
"member_subgroup"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "exercise",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Exercise",
|
||||
"options": "Exercise",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Correct\nIncorrect"
|
||||
},
|
||||
{
|
||||
"fieldname": "batch",
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch",
|
||||
"options": "LMS Batch"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.title",
|
||||
"fieldname": "exercise_title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Exercise Title",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.lesson",
|
||||
"fieldname": "lesson",
|
||||
"fieldtype": "Link",
|
||||
"label": "Lesson",
|
||||
"options": "Course Lesson"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "latest_submission.solution",
|
||||
"fieldname": "solution",
|
||||
"fieldtype": "Code",
|
||||
"label": "Solution"
|
||||
},
|
||||
{
|
||||
"fetch_from": "latest_submission.image",
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Code",
|
||||
"label": "Image",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "latest_submission.test_results",
|
||||
"fieldname": "test_results",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Test Results"
|
||||
},
|
||||
{
|
||||
"fieldname": "comments",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Comments"
|
||||
},
|
||||
{
|
||||
"fieldname": "latest_submission",
|
||||
"fieldtype": "Link",
|
||||
"label": "Latest Submission",
|
||||
"options": "Exercise Submission"
|
||||
},
|
||||
{
|
||||
"fieldname": "member",
|
||||
"fieldtype": "Link",
|
||||
"label": "Member",
|
||||
"options": "LMS Batch Membership"
|
||||
},
|
||||
{
|
||||
"fetch_from": "member.member",
|
||||
"fieldname": "member_email",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Member Email",
|
||||
"options": "User",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "member.cohort",
|
||||
"fieldname": "member_cohort",
|
||||
"fieldtype": "Link",
|
||||
"label": "Member Cohort",
|
||||
"options": "Cohort",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "member.subgroup",
|
||||
"fieldname": "member_subgroup",
|
||||
"fieldtype": "Link",
|
||||
"label": "Member Subgroup",
|
||||
"options": "Cohort Subgroup",
|
||||
"search_index": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-08 22:58:46.312861",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Exercise Latest Submission",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ExerciseLatestSubmission(Document):
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestExerciseLatestSubmission(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/exercise_submission/__init__.py
Normal file
0
lms/lms/doctype/exercise_submission/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise Submission', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
126
lms/lms/doctype/exercise_submission/exercise_submission.json
Normal file
126
lms/lms/doctype/exercise_submission/exercise_submission.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-19 11:41:18.108316",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"exercise",
|
||||
"status",
|
||||
"batch",
|
||||
"column_break_4",
|
||||
"exercise_title",
|
||||
"course",
|
||||
"lesson",
|
||||
"section_break_8",
|
||||
"solution",
|
||||
"image",
|
||||
"test_results",
|
||||
"comments",
|
||||
"member"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "exercise",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Exercise",
|
||||
"options": "Exercise"
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.title",
|
||||
"fieldname": "exercise_title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Exercise Title",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.course",
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"label": "Course",
|
||||
"options": "LMS Course",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "batch",
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch",
|
||||
"options": "LMS Batch"
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise.lesson",
|
||||
"fieldname": "lesson",
|
||||
"fieldtype": "Link",
|
||||
"label": "Lesson",
|
||||
"options": "Course Lesson"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Code",
|
||||
"label": "Image",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Correct\nIncorrect"
|
||||
},
|
||||
{
|
||||
"fieldname": "test_results",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Test Results"
|
||||
},
|
||||
{
|
||||
"fieldname": "comments",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Comments"
|
||||
},
|
||||
{
|
||||
"fieldname": "solution",
|
||||
"fieldtype": "Code",
|
||||
"in_list_view": 1,
|
||||
"label": "Solution"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "member",
|
||||
"fieldtype": "Link",
|
||||
"label": "Member",
|
||||
"options": "LMS Batch Membership"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-08 22:25:05.809376",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Exercise Submission",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
24
lms/lms/doctype/exercise_submission/exercise_submission.py
Normal file
24
lms/lms/doctype/exercise_submission/exercise_submission.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ExerciseSubmission(Document):
|
||||
def on_update(self):
|
||||
self.update_latest_submission()
|
||||
|
||||
def update_latest_submission(self):
|
||||
names = frappe.get_all("Exercise Latest Submission", {"exercise": self.exercise, "member": self.member})
|
||||
if names:
|
||||
doc = frappe.get_doc("Exercise Latest Submission", names[0])
|
||||
doc.latest_submission = self.name
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Exercise Latest Submission",
|
||||
"exercise": self.exercise,
|
||||
"member": self.member,
|
||||
"latest_submission": self.name
|
||||
})
|
||||
doc.insert(ignore_permissions=True)
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestExerciseSubmission(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/function/__init__.py
Normal file
0
lms/lms/doctype/function/__init__.py
Normal file
8
lms/lms/doctype/function/function.js
Normal file
8
lms/lms/doctype/function/function.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Function', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
54
lms/lms/doctype/function/function.json
Normal file
54
lms/lms/doctype/function/function.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:function",
|
||||
"creation": "2021-12-14 14:02:35.435916",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"function"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "function",
|
||||
"fieldtype": "Data",
|
||||
"label": "Function",
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-21 09:34:35.018280",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Function",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"select": 1,
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
8
lms/lms/doctype/function/function.py
Normal file
8
lms/lms/doctype/function/function.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Function(Document):
|
||||
pass
|
||||
8
lms/lms/doctype/function/test_function.py
Normal file
8
lms/lms/doctype/function/test_function.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestFunction(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/industry/__init__.py
Normal file
0
lms/lms/doctype/industry/__init__.py
Normal file
8
lms/lms/doctype/industry/industry.js
Normal file
8
lms/lms/doctype/industry/industry.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Industry', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
54
lms/lms/doctype/industry/industry.json
Normal file
54
lms/lms/doctype/industry/industry.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:industry",
|
||||
"creation": "2021-12-14 14:37:47.183595",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"industry"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "industry",
|
||||
"fieldtype": "Data",
|
||||
"label": "Industry",
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-21 09:35:20.443192",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Industry",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"select": 1,
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
8
lms/lms/doctype/industry/industry.py
Normal file
8
lms/lms/doctype/industry/industry.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Industry(Document):
|
||||
pass
|
||||
8
lms/lms/doctype/industry/test_industry.py
Normal file
8
lms/lms/doctype/industry/test_industry.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestIndustry(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/invite_request/__init__.py
Normal file
0
lms/lms/doctype/invite_request/__init__.py
Normal file
8
lms/lms/doctype/invite_request/invite_request.js
Normal file
8
lms/lms/doctype/invite_request/invite_request.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Invite Request', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
88
lms/lms/doctype/invite_request/invite_request.json
Normal file
88
lms/lms/doctype/invite_request/invite_request.json
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-04-29 16:29:56.857914",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"invite_email",
|
||||
"signup_email",
|
||||
"column_break_4",
|
||||
"status",
|
||||
"full_name",
|
||||
"username",
|
||||
"invite_code"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_in_quick_entry": 1,
|
||||
"fieldname": "invite_email",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Invite Email",
|
||||
"options": "Email",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "full_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Full Name"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "signup_email",
|
||||
"fieldtype": "Data",
|
||||
"label": "Signup Email",
|
||||
"options": "Email"
|
||||
},
|
||||
{
|
||||
"fieldname": "username",
|
||||
"fieldtype": "Data",
|
||||
"label": "Username"
|
||||
},
|
||||
{
|
||||
"fieldname": "invite_code",
|
||||
"fieldtype": "Data",
|
||||
"label": "Invite Code"
|
||||
},
|
||||
{
|
||||
"default": "Pending",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"options": "Pending\nApproved\nRejected\nRegistered"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-03 09:22:20.954921",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Invite Request",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"search_fields": "invite_email, signup_email",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "invite_email",
|
||||
"track_changes": 1
|
||||
}
|
||||
90
lms/lms/doctype/invite_request/invite_request.py
Normal file
90
lms/lms/doctype/invite_request/invite_request.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
import json
|
||||
from frappe.utils.password import get_decrypted_password
|
||||
|
||||
class InviteRequest(Document):
|
||||
def on_update(self):
|
||||
if self.has_value_changed("status") and self.status == "Approved":
|
||||
self.send_email()
|
||||
|
||||
def create_user(self, password):
|
||||
full_name_split = self.full_name.split(" ")
|
||||
user = frappe.get_doc({
|
||||
"doctype": "User",
|
||||
"email": self.signup_email,
|
||||
"first_name": full_name_split[0],
|
||||
"last_name": full_name_split[1] if len(full_name_split) > 1 else "",
|
||||
"username": self.username,
|
||||
"send_welcome_email": 0,
|
||||
"user_type": "Website User",
|
||||
"new_password": password
|
||||
})
|
||||
user.save(ignore_permissions=True)
|
||||
return user
|
||||
|
||||
def send_email(self):
|
||||
site_name = "Mon.School"
|
||||
subject = _("Welcome to {0}!").format(site_name)
|
||||
|
||||
args = {
|
||||
"full_name": self.full_name,
|
||||
"signup_form_link": "/new-sign-up?invite_code={0}".format(self.name),
|
||||
"site_name": site_name,
|
||||
"site_url": frappe.utils.get_url()
|
||||
}
|
||||
frappe.sendmail(
|
||||
recipients=self.invite_email,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template = "lms_invite_request_approved",
|
||||
args=args,
|
||||
now=True)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def create_invite_request(invite_email):
|
||||
|
||||
if not frappe.utils.validate_email_address(invite_email):
|
||||
return "invalid email"
|
||||
|
||||
if frappe.db.exists("User", invite_email):
|
||||
return "user"
|
||||
|
||||
if frappe.db.exists("Invite Request", {"invite_email": invite_email}):
|
||||
return "invite"
|
||||
|
||||
frappe.get_doc({
|
||||
"doctype": "Invite Request",
|
||||
"invite_email": invite_email,
|
||||
"status": "Approved"
|
||||
}).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def update_invite(data):
|
||||
data = frappe._dict(json.loads(data)) if type(data) == str else frappe._dict(data)
|
||||
|
||||
try:
|
||||
doc = frappe.get_doc("Invite Request", data.invite_code)
|
||||
except frappe.DoesNotExistError:
|
||||
frappe.throw(_("Invalid Invite Code."))
|
||||
|
||||
doc.signup_email = data.signup_email
|
||||
doc.username = data.username
|
||||
doc.full_name = data.full_name
|
||||
doc.invite_code = data.invite_code
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
user = doc.create_user(data.password)
|
||||
if user:
|
||||
doc.status = "Registered"
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
return "OK"
|
||||
62
lms/lms/doctype/invite_request/test_invite_request.py
Normal file
62
lms/lms/doctype/invite_request/test_invite_request.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
from lms.lms.doctype.invite_request.invite_request import create_invite_request, update_invite
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestInviteRequest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
create_invite_request("test_invite@example.com")
|
||||
|
||||
def test_create_invite_request(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
invite = frappe.db.get_value("Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=["invite_email", "status", "signup_email"],
|
||||
as_dict=True)
|
||||
self.assertEqual(invite.status, "Approved")
|
||||
self.assertEqual(invite.signup_email, None)
|
||||
|
||||
def test_create_invite_request_update(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
|
||||
data = {
|
||||
"signup_email": "test_invite@example.com",
|
||||
"username": "test_invite",
|
||||
"full_name": "Test Invite",
|
||||
"password": "Test@invite",
|
||||
"invite_code": frappe.db.get_value("Invite Request", {"invite_email": "test_invite@example.com"}, "name")
|
||||
}
|
||||
|
||||
update_invite(data)
|
||||
invite = frappe.db.get_value("Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=["invite_email", "status", "signup_email", "full_name", "username", "invite_code", "name"],
|
||||
as_dict=True)
|
||||
self.assertEqual(invite.signup_email, "test_invite@example.com")
|
||||
self.assertEqual(invite.full_name, "Test Invite")
|
||||
self.assertEqual(invite.username, "test_invite")
|
||||
self.assertEqual(invite.invite_code, invite.name)
|
||||
self.assertEqual(invite.status, "Registered")
|
||||
|
||||
user = frappe.db.get_value("User", "test_invite@example.com",
|
||||
fieldname=["first_name", "username", "send_welcome_email", "user_type"],
|
||||
as_dict=True)
|
||||
self.assertTrue(user)
|
||||
self.assertEqual(user.first_name, invite.full_name.split(" ")[0])
|
||||
self.assertEqual(user.username, invite.username)
|
||||
self.assertEqual(user.send_welcome_email, 0)
|
||||
self.assertEqual(user.user_type, "Website User")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
if frappe.db.exists("User", "test_invite@example.com"):
|
||||
frappe.delete_doc("User", "test_invite@example.com")
|
||||
|
||||
invite_request = frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"})
|
||||
if invite_request:
|
||||
frappe.delete_doc("Invite Request", invite_request)
|
||||
0
lms/lms/doctype/lesson_assignment/__init__.py
Normal file
0
lms/lms/doctype/lesson_assignment/__init__.py
Normal file
8
lms/lms/doctype/lesson_assignment/lesson_assignment.js
Normal file
8
lms/lms/doctype/lesson_assignment/lesson_assignment.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Lesson Assignment', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
70
lms/lms/doctype/lesson_assignment/lesson_assignment.json
Normal file
70
lms/lms/doctype/lesson_assignment/lesson_assignment.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2021-12-21 16:15:22.651658",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"lesson",
|
||||
"user",
|
||||
"column_break_3",
|
||||
"assignment",
|
||||
"id"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "lesson",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Lesson",
|
||||
"options": "Course Lesson"
|
||||
},
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "User",
|
||||
"options": "User"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "id",
|
||||
"fieldtype": "Data",
|
||||
"label": "ID"
|
||||
},
|
||||
{
|
||||
"fieldname": "assignment",
|
||||
"fieldtype": "Attach",
|
||||
"label": "Assignment"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-22 11:17:08.390615",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Lesson Assignment",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
43
lms/lms/doctype/lesson_assignment/lesson_assignment.py
Normal file
43
lms/lms/doctype/lesson_assignment/lesson_assignment.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.handler import upload_file
|
||||
|
||||
class LessonAssignment(Document):
|
||||
pass
|
||||
|
||||
@frappe.whitelist()
|
||||
def upload_assignment(assignment, lesson, identifier):
|
||||
args = {
|
||||
"doctype": "Lesson Assignment",
|
||||
"lesson": lesson,
|
||||
"user": frappe.session.user,
|
||||
"id": identifier
|
||||
}
|
||||
if frappe.db.exists(args):
|
||||
del args["doctype"]
|
||||
frappe.db.set_value("Lesson Assignment", args, "assignment", assignment)
|
||||
else:
|
||||
args.update({"assignment": assignment})
|
||||
lesson_work = frappe.get_doc(args)
|
||||
lesson_work.save(ignore_permissions=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_assignment(lesson):
|
||||
assignments = frappe.get_all("Lesson Assignment",
|
||||
{
|
||||
"lesson": lesson,
|
||||
"user": frappe.session.user
|
||||
},
|
||||
["lesson", "user", "id", "assignment"])
|
||||
if len(assignments):
|
||||
for assignment in assignments:
|
||||
assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name")
|
||||
return assignments
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestLessonAssignment(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/lesson_reference/__init__.py
Normal file
0
lms/lms/doctype/lesson_reference/__init__.py
Normal file
35
lms/lms/doctype/lesson_reference/lesson_reference.json
Normal file
35
lms/lms/doctype/lesson_reference/lesson_reference.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2021-07-27 16:25:48.269536",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"lesson"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "lesson",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Lesson",
|
||||
"options": "Course Lesson",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-15 09:39:29.495991",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "Lesson Reference",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
8
lms/lms/doctype/lesson_reference/lesson_reference.py
Normal file
8
lms/lms/doctype/lesson_reference/lesson_reference.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class LessonReference(Document):
|
||||
pass
|
||||
0
lms/lms/doctype/lms_batch/__init__.py
Normal file
0
lms/lms/doctype/lms_batch/__init__.py
Normal file
8
lms/lms/doctype/lms_batch/lms_batch.js
Normal file
8
lms/lms/doctype/lms_batch/lms_batch.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Batch', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
145
lms/lms/doctype/lms_batch/lms_batch.json
Normal file
145
lms/lms/doctype/lms_batch/lms_batch.json
Normal file
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-03-18 19:37:34.614796",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"course",
|
||||
"start_date",
|
||||
"start_time",
|
||||
"column_break_3",
|
||||
"title",
|
||||
"sessions_on",
|
||||
"end_time",
|
||||
"section_break_5",
|
||||
"description",
|
||||
"section_break_7",
|
||||
"visibility",
|
||||
"membership",
|
||||
"column_break_9",
|
||||
"status",
|
||||
"stage"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "course",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course"
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title"
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"default": "Public",
|
||||
"fieldname": "visibility",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Visibility",
|
||||
"options": "Public\nUnlisted\nPrivate"
|
||||
},
|
||||
{
|
||||
"fieldname": "membership",
|
||||
"fieldtype": "Select",
|
||||
"label": "Membership",
|
||||
"options": "\nOpen\nRestricted\nInvite Only\nClosed"
|
||||
},
|
||||
{
|
||||
"default": "Active",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Active\nInactive"
|
||||
},
|
||||
{
|
||||
"default": "Ready",
|
||||
"fieldname": "stage",
|
||||
"fieldtype": "Select",
|
||||
"label": "Stage",
|
||||
"options": "Ready\nIn Progress\nCompleted\nCancelled"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Batch Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Batch Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Start Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "start_time",
|
||||
"fieldtype": "Time",
|
||||
"in_list_view": 1,
|
||||
"label": "Start Time"
|
||||
},
|
||||
{
|
||||
"fieldname": "sessions_on",
|
||||
"fieldtype": "Data",
|
||||
"label": "Sessions On Days"
|
||||
},
|
||||
{
|
||||
"fieldname": "end_time",
|
||||
"fieldtype": "Time",
|
||||
"in_list_view": 1,
|
||||
"label": "End Time"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Members",
|
||||
"link_doctype": "LMS Batch Membership",
|
||||
"link_fieldname": "batch"
|
||||
}
|
||||
],
|
||||
"modified": "2021-06-16 10:51:05.403726",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Batch",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
100
lms/lms/doctype/lms_batch/lms_batch.py
Normal file
100
lms/lms/doctype/lms_batch/lms_batch.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from lms.lms.doctype.lms_batch_membership.lms_batch_membership import create_membership
|
||||
from lms.query import find, find_all
|
||||
from lms.lms.utils import is_mentor
|
||||
|
||||
class LMSBatch(Document):
|
||||
def validate(self):
|
||||
self.validate_if_mentor()
|
||||
|
||||
def validate_if_mentor(self):
|
||||
if not is_mentor(self.course, frappe.session.user):
|
||||
frappe.throw(_("You are not a mentor of the course {0}").format(course.title))
|
||||
|
||||
def after_insert(self):
|
||||
create_membership(batch=self.name, course=self.course, member_type="Mentor")
|
||||
|
||||
def is_member(self, email, member_type=None):
|
||||
"""Checks if a person is part of a batch.
|
||||
|
||||
If member_type is specified, checks if the person is a Student/Mentor.
|
||||
"""
|
||||
|
||||
filters = {
|
||||
"batch": self.name,
|
||||
"member": email
|
||||
}
|
||||
if member_type:
|
||||
filters['member_type'] = member_type
|
||||
return frappe.db.exists("LMS Batch Membership", filters)
|
||||
|
||||
|
||||
def get_membership(self, email):
|
||||
"""Returns the membership document of given user.
|
||||
"""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={
|
||||
"batch": self.name,
|
||||
"member": email
|
||||
},
|
||||
fieldname="name")
|
||||
return frappe.get_doc("LMS Batch Membership", name)
|
||||
|
||||
def get_current_lesson(self, user):
|
||||
"""Returns the name of the current lesson for the given user.
|
||||
"""
|
||||
membership = self.get_membership(user)
|
||||
return membership and membership.current_lesson
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_message(message, batch):
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Message",
|
||||
"batch": batch,
|
||||
"author": frappe.session.user,
|
||||
"message": message
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
def switch_batch(course_name, email, batch_name):
|
||||
"""Switches the user from the current batch of the course to a new batch.
|
||||
"""
|
||||
membership = frappe.get_last_doc(
|
||||
"LMS Batch Membership",
|
||||
filters={"course": course_name, "member": email})
|
||||
|
||||
batch = frappe.get_doc("LMS Batch", batch_name)
|
||||
if not batch:
|
||||
raise ValueError(f"Invalid Batch: {batch_name}")
|
||||
|
||||
if batch.course != course_name:
|
||||
raise ValueError("Can not switch batches across courses")
|
||||
|
||||
if batch.is_member(email):
|
||||
print(f"{email} is already a member of {batch.title}")
|
||||
return
|
||||
|
||||
old_batch = frappe.get_doc("LMS Batch", membership.batch)
|
||||
|
||||
print("updating membership", membership.name)
|
||||
membership.batch = batch_name
|
||||
membership.save()
|
||||
|
||||
# update exercise submissions
|
||||
filters = {
|
||||
"owner": email,
|
||||
"batch": old_batch.name
|
||||
}
|
||||
for name in frappe.db.get_all("Exercise Submission", filters=filters, pluck='name'):
|
||||
doc = frappe.get_doc("Exercise Submission", name)
|
||||
print("updating exercise submission", name)
|
||||
doc.batch = batch_name
|
||||
doc.save()
|
||||
10
lms/lms/doctype/lms_batch/test_lms_batch.py
Normal file
10
lms/lms/doctype/lms_batch/test_lms_batch.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestLMSBatch(unittest.TestCase):
|
||||
pass
|
||||
0
lms/lms/doctype/lms_batch_membership/__init__.py
Normal file
0
lms/lms/doctype/lms_batch_membership/__init__.py
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user