fix: pre commit issues

This commit is contained in:
Jannat Patel
2022-11-04 11:47:09 +05:30
parent cda26ab248
commit 603eddf878
210 changed files with 10725 additions and 6733 deletions

View File

@@ -1,4 +1 @@
# -*- coding: utf-8 -*- __version__ = "0.0.1"
from __future__ import unicode_literals
__version__ = '0.0.1'

View File

@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from frappe import _ from frappe import _
def get_data(): def get_data():
return [ return [
{ {
@@ -9,6 +8,6 @@ def get_data():
"color": "grey", "color": "grey",
"icon": "octicon octicon-file-directory", "icon": "octicon octicon-file-directory",
"type": "module", "type": "module",
"label": _("Community") "label": _("Community"),
} }
] ]

View File

@@ -7,5 +7,6 @@ Configuration for docs
# headline = "App that does everything" # headline = "App that does everything"
# sub_heading = "Yes, you got that right the first time, everything" # sub_heading = "Yes, you got that right the first time, everything"
def get_context(context): def get_context(context):
context.brand_html = "Community" context.brand_html = "Community"

View File

@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from . import __version__ as app_version from . import __version__ as app_version
app_name = "frappe_lms" app_name = "frappe_lms"
@@ -88,7 +86,7 @@ after_uninstall = "lms.install.after_uninstall"
override_doctype_class = { override_doctype_class = {
"User": "lms.overrides.user.CustomUser", "User": "lms.overrides.user.CustomUser",
"Web Template": "lms.overrides.web_template.CustomWebTemplate" "Web Template": "lms.overrides.web_template.CustomWebTemplate",
} }
# Document Events # Document Events
@@ -96,9 +94,7 @@ override_doctype_class = {
# Hook on document methods and events # Hook on document methods and events
doc_events = { doc_events = {
"Discussion Reply": { "Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"}
"after_insert": "lms.lms.utils.create_notification_log"
}
} }
# Scheduled Tasks # Scheduled Tasks
@@ -140,19 +136,34 @@ website_route_rules = [
{"from_route": "/courses/<course>", "to_route": "courses/course"}, {"from_route": "/courses/<course>", "to_route": "courses/course"},
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"}, {"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
{"from_route": "/courses/<course>/learn", "to_route": "batch/learn"}, {"from_route": "/courses/<course>/learn", "to_route": "batch/learn"},
{"from_route": "/courses/<course>/learn/<int:chapter>.<int:lesson>", "to_route": "batch/learn"}, {
"from_route": "/courses/<course>/learn/<int:chapter>.<int:lesson>",
"to_route": "batch/learn",
},
{"from_route": "/quizzes", "to_route": "batch/quiz_list"}, {"from_route": "/quizzes", "to_route": "batch/quiz_list"},
{"from_route": "/quizzes/<quizname>", "to_route": "batch/quiz"}, {"from_route": "/quizzes/<quizname>", "to_route": "batch/quiz"},
{"from_route": "/courses/<course>/progress", "to_route": "batch/progress"}, {"from_route": "/courses/<course>/progress", "to_route": "batch/progress"},
{"from_route": "/courses/<course>/join", "to_route": "batch/join"}, {"from_route": "/courses/<course>/join", "to_route": "batch/join"},
{"from_route": "/courses/<course>/manage", "to_route": "cohorts"}, {"from_route": "/courses/<course>/manage", "to_route": "cohorts"},
{"from_route": "/courses/<course>/cohorts/<cohort>", "to_route": "cohorts/cohort"}, {"from_route": "/courses/<course>/cohorts/<cohort>", "to_route": "cohorts/cohort"},
{"from_route": "/courses/<course>/cohorts/<cohort>/<page>", "to_route": "cohorts/cohort"}, {
{"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>", "to_route": "cohorts/subgroup"}, "from_route": "/courses/<course>/cohorts/<cohort>/<page>",
{"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>/<page>", "to_route": "cohorts/subgroup"}, "to_route": "cohorts/cohort",
{"from_route": "/courses/<course>/join/<cohort>/<subgroup>/<invite_code>", "to_route": "cohorts/join"}, },
{
"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>",
"to_route": "cohorts/subgroup",
},
{
"from_route": "/courses/<course>/subgroups/<cohort>/<subgroup>/<page>",
"to_route": "cohorts/subgroup",
},
{
"from_route": "/courses/<course>/join/<cohort>/<subgroup>/<invite_code>",
"to_route": "cohorts/join",
},
{"from_route": "/users", "to_route": "profiles/profile"}, {"from_route": "/users", "to_route": "profiles/profile"},
{"from_route": "/jobs/<job>", "to_route": "jobs/job"} {"from_route": "/jobs/<job>", "to_route": "jobs/job"},
] ]
website_redirects = [ website_redirects = [
@@ -161,7 +172,7 @@ website_redirects = [
] ]
update_website_context = [ update_website_context = [
'lms.widgets.update_website_context', "lms.widgets.update_website_context",
] ]
jinja = { jinja = {
@@ -206,9 +217,9 @@ jinja = {
"lms.lms.utils.get_all_memberships", "lms.lms.utils.get_all_memberships",
"lms.lms.utils.get_filtered_membership", "lms.lms.utils.get_filtered_membership",
"lms.lms.utils.show_start_learing_cta", "lms.lms.utils.show_start_learing_cta",
"lms.lms.utils.can_create_courses" "lms.lms.utils.can_create_courses",
], ],
"filters": [] "filters": [],
} }
## Specify the additional tabs to be included in the user profile page. ## Specify the additional tabs to be included in the user profile page.
## Each entry must be a subclass of lms.lms.plugins.ProfileTab ## Each entry must be a subclass of lms.lms.plugins.ProfileTab
@@ -239,7 +250,7 @@ profile_mandatory_fields = [
"role", "role",
"location_preference", "location_preference",
"time", "time",
"company_type" "company_type",
] ]
## Markdown Macros for Lessons ## Markdown Macros for Lessons
@@ -248,13 +259,13 @@ lms_markdown_macro_renderers = {
"Quiz": "lms.plugins.quiz_renderer", "Quiz": "lms.plugins.quiz_renderer",
"YouTubeVideo": "lms.plugins.youtube_video_renderer", "YouTubeVideo": "lms.plugins.youtube_video_renderer",
"Video": "lms.plugins.video_renderer", "Video": "lms.plugins.video_renderer",
"Assignment": "lms.plugins.assignment_renderer" "Assignment": "lms.plugins.assignment_renderer",
} }
# page_renderer to manage profile pages # page_renderer to manage profile pages
page_renderer = [ page_renderer = [
"lms.page_renderers.ProfileRedirectPage", "lms.page_renderers.ProfileRedirectPage",
"lms.page_renderers.ProfilePage" "lms.page_renderers.ProfilePage",
] ]
# set this to "/" to have profiles on the top-level # set this to "/" to have profiles on the top-level

View File

@@ -23,36 +23,69 @@ def set_default_home():
def create_instructor_role(): def create_instructor_role():
if not frappe.db.exists("Role", "Course Instructor"): if not frappe.db.exists("Role", "Course Instructor"):
role = frappe.get_doc({ role = frappe.get_doc(
{
"doctype": "Role", "doctype": "Role",
"role_name": "Course Instructor", "role_name": "Course Instructor",
"home_page": "", "home_page": "",
"desk_access": 0 "desk_access": 0,
}) }
)
role.save(ignore_permissions=True) role.save(ignore_permissions=True)
def create_moderator_role(): def create_moderator_role():
if not frappe.db.exists("Role", "Course Moderator"): if not frappe.db.exists("Role", "Course Moderator"):
role = frappe.get_doc({ role = frappe.get_doc(
{
"doctype": "Role", "doctype": "Role",
"role_name": "Course Moderator", "role_name": "Course Moderator",
"home_page": "", "home_page": "",
"desk_access": 0 "desk_access": 0,
}) }
)
role.save(ignore_permissions=True) role.save(ignore_permissions=True)
def delete_custom_fields(): def delete_custom_fields():
fields = [ "user_category", "headline", "college", "city", "verify_terms", "country", fields = [
"preferred_location", "preferred_functions", "preferred_industries", "user_category",
"work_environment_column", "time", "role", "carrer_preference_details", "headline",
"skill", "certification_details", "internship", "branch", "github", "college",
"medium", "linkedin", "profession", "looking_for_job", "cover_image" "city",
"work_environment", "dream_companies", "career_preference_column", "verify_terms",
"attire", "collaboration", "location_preference", "company_type", "country",
"skill_details", "certification", "education", "work_experience", "preferred_location",
"education_details", "hide_private", "work_experience_details", "profile_complete" "preferred_functions",
"preferred_industries",
"work_environment_column",
"time",
"role",
"carrer_preference_details",
"skill",
"certification_details",
"internship",
"branch",
"github",
"medium",
"linkedin",
"profession",
"looking_for_job",
"cover_image" "work_environment",
"dream_companies",
"career_preference_column",
"attire",
"collaboration",
"location_preference",
"company_type",
"skill_details",
"certification",
"education",
"work_experience",
"education_details",
"hide_private",
"work_experience_details",
"profile_complete",
] ]
for field in fields: for field in fields:

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Job Opportunity', { frappe.ui.form.on("Job Opportunity", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,20 +2,19 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe.model.document import Document
from frappe.utils.user import get_system_managers
from frappe import _ from frappe import _
from frappe.model.document import Document
from frappe.utils import get_link_to_form from frappe.utils import get_link_to_form
from frappe.utils.user import get_system_managers
from lms.lms.utils import validate_image from lms.lms.utils import validate_image
class JobOpportunity(Document): class JobOpportunity(Document):
def validate(self): def validate(self):
self.validate_urls() self.validate_urls()
self.company_logo = validate_image(self.company_logo) self.company_logo = validate_image(self.company_logo)
def validate_urls(self): def validate_urls(self):
frappe.utils.validate_url(self.company_website, True) frappe.utils.validate_url(self.company_website, True)
frappe.utils.validate_url(self.application_link, True) frappe.utils.validate_url(self.application_link, True)
@@ -30,7 +29,7 @@ def report(job, reason):
"job": job, "job": job,
"job_url": get_link_to_form("Job Opportunity", job), "job_url": get_link_to_form("Job Opportunity", job),
"user": user, "user": user,
"reason": reason "reason": reason,
} }
frappe.sendmail( frappe.sendmail(
recipients=system_managers, recipients=system_managers,
@@ -38,4 +37,5 @@ def report(job, reason):
header=[subject, "green"], header=[subject, "green"],
template="job_report", template="job_report",
args=args, args=args,
now=True) now=True,
)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestJobOpportunity(unittest.TestCase): class TestJobOpportunity(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2022, Frappe and contributors // Copyright (c) 2022, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Job Settings', { frappe.ui.form.on("Job Settings", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class JobSettings(Document): class JobSettings(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestJobSettings(unittest.TestCase): class TestJobSettings(unittest.TestCase):
pass pass

View File

@@ -1,5 +1,6 @@
import frappe import frappe
def get_context(context): def get_context(context):
# do your magic here # do your magic here
pass pass

View File

@@ -2,6 +2,6 @@ frappe.ready(function() {
frappe.web_form.after_save = () => { frappe.web_form.after_save = () => {
setTimeout(() => { setTimeout(() => {
window.location.href = `/jobs`; window.location.href = `/jobs`;
}) });
} };
}) });

View File

@@ -1,5 +1,6 @@
import frappe import frappe
def get_context(context): def get_context(context):
# do your magic here # do your magic here
pass pass

View File

@@ -3,18 +3,17 @@
import frappe import frappe
@frappe.whitelist() @frappe.whitelist()
def autosave_section(section, code): def autosave_section(section, code):
"""Saves the code edited in one of the sections. """Saves the code edited in one of the sections."""
"""
doc = frappe.get_doc( doc = frappe.get_doc(
doctype="Code Revision", doctype="Code Revision", section=section, code=code, author=frappe.session.user
section=section, )
code=code,
author=frappe.session.user)
doc.insert() doc.insert()
return {"name": doc.name} return {"name": doc.name}
@frappe.whitelist() @frappe.whitelist()
def submit_solution(exercise, code): def submit_solution(exercise, code):
"""Submits a solution. """Submits a solution.
@@ -28,17 +27,15 @@ def submit_solution(exercise, code):
doc = ex.submit(code) doc = ex.submit(code)
return {"name": doc.name, "creation": doc.creation} return {"name": doc.name, "creation": doc.creation}
@frappe.whitelist() @frappe.whitelist()
def save_current_lesson(course_name, lesson_name): def save_current_lesson(course_name, lesson_name):
"""Saves the current lesson for a student/mentor. """Saves the current lesson for a student/mentor."""
"""
name = frappe.get_value( name = frappe.get_value(
doctype="LMS Batch Membership", doctype="LMS Batch Membership",
filters={ filters={"course": course_name, "member": frappe.session.user},
"course": course_name, fieldname="name",
"member": frappe.session.user )
},
fieldname="name")
if not name: if not name:
return return
doc = frappe.get_doc("LMS Batch Membership", name) doc = frappe.get_doc("LMS Batch Membership", name)
@@ -49,24 +46,20 @@ def save_current_lesson(course_name, lesson_name):
@frappe.whitelist() @frappe.whitelist()
def join_cohort(course, cohort, subgroup, invite_code): def join_cohort(course, cohort, subgroup, invite_code):
"""Creates a Cohort Join Request for given user. """Creates a Cohort Join Request for given user."""
"""
course_doc = frappe.get_doc("LMS Course", course) course_doc = frappe.get_doc("LMS Course", course)
cohort_doc = course_doc and course_doc.get_cohort(cohort) cohort_doc = course_doc and course_doc.get_cohort(cohort)
subgroup_doc = cohort_doc and cohort_doc.get_subgroup(subgroup) subgroup_doc = cohort_doc and cohort_doc.get_subgroup(subgroup)
if not subgroup_doc or subgroup_doc.invite_code != invite_code: if not subgroup_doc or subgroup_doc.invite_code != invite_code:
return { return {"ok": False, "error": "Invalid join link"}
"ok": False,
"error": "Invalid join link"
}
data = { data = {
"doctype": "Cohort Join Request", "doctype": "Cohort Join Request",
"cohort": cohort_doc.name, "cohort": cohort_doc.name,
"subgroup": subgroup_doc.name, "subgroup": subgroup_doc.name,
"email": frappe.session.user, "email": frappe.session.user,
"status": "Pending" "status": "Pending",
} }
# Don't insert duplicate records # Don't insert duplicate records
if frappe.db.exists(data): if frappe.db.exists(data):
@@ -76,39 +69,33 @@ def join_cohort(course, cohort, subgroup, invite_code):
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)
return {"ok": True, "status": "record created"} return {"ok": True, "status": "record created"}
@frappe.whitelist() @frappe.whitelist()
def approve_cohort_join_request(join_request): def approve_cohort_join_request(join_request):
r = frappe.get_doc("Cohort Join Request", join_request) r = frappe.get_doc("Cohort Join Request", join_request)
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup) sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
if not sg or r.status not in ["Pending", "Accepted"]: if not sg or r.status not in ["Pending", "Accepted"]:
return { return {"ok": False, "error": "Invalid Join Request"}
"ok": False, if (
"error": "Invalid Join Request" not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
} ):
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles(): return {"ok": False, "error": "Permission Deined"}
return {
"ok": False,
"error": "Permission Deined"
}
r.status = "Accepted" r.status = "Accepted"
r.save(ignore_permissions=True) r.save(ignore_permissions=True)
return {"ok": True} return {"ok": True}
@frappe.whitelist() @frappe.whitelist()
def reject_cohort_join_request(join_request): def reject_cohort_join_request(join_request):
r = frappe.get_doc("Cohort Join Request", join_request) r = frappe.get_doc("Cohort Join Request", join_request)
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup) sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
if not sg or r.status not in ["Pending", "Rejected"]: if not sg or r.status not in ["Pending", "Rejected"]:
return { return {"ok": False, "error": "Invalid Join Request"}
"ok": False, if (
"error": "Invalid Join Request" not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
} ):
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles(): return {"ok": False, "error": "Permission Deined"}
return {
"ok": False,
"error": "Permission Deined"
}
r.status = "Rejected" r.status = "Rejected"
r.save(ignore_permissions=True) r.save(ignore_permissions=True)
@@ -121,43 +108,34 @@ def undo_reject_cohort_join_request(join_request):
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup) sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
# keeping Pending as well to consider the case of duplicate requests # keeping Pending as well to consider the case of duplicate requests
if not sg or r.status not in ["Pending", "Rejected"]: if not sg or r.status not in ["Pending", "Rejected"]:
return { return {"ok": False, "error": "Invalid Join Request"}
"ok": False, if (
"error": "Invalid Join Request" not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
} ):
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles(): return {"ok": False, "error": "Permission Deined"}
return {
"ok": False,
"error": "Permission Deined"
}
r.status = "Pending" r.status = "Pending"
r.save(ignore_permissions=True) r.save(ignore_permissions=True)
return {"ok": True} return {"ok": True}
@frappe.whitelist() @frappe.whitelist()
def add_mentor_to_subgroup(subgroup, email): def add_mentor_to_subgroup(subgroup, email):
try: try:
sg = frappe.get_doc("Cohort Subgroup", subgroup) sg = frappe.get_doc("Cohort Subgroup", subgroup)
except frappe.DoesNotExistError: except frappe.DoesNotExistError:
return { return {"ok": False, "error": f"Invalid subgroup: {subgroup}"}
"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(): if (
return { not sg.get_cohort().is_admin(frappe.session.user)
"ok": False, and "System Manager" not in frappe.get_roles()
"error": "Permission Deined" ):
} return {"ok": False, "error": "Permission Deined"}
try: try:
user = frappe.get_doc("User", email) user = frappe.get_doc("User", email)
except frappe.DoesNotExistError: except frappe.DoesNotExistError:
return { return {"ok": False, "error": f"Invalid user: {email}"}
"ok": False,
"error": f"Invalid user: {email}"
}
sg.add_mentor(email) sg.add_mentor(email)
return {"ok": True} return {"ok": True}

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Certification', { frappe.ui.form.on("Certification", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Certification(Document): class Certification(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCertification(unittest.TestCase): class TestCertification(unittest.TestCase):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class ChapterReference(Document): class ChapterReference(Document):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Cohort', { frappe.ui.form.on("Cohort", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,6 +4,7 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Cohort(Document): class Cohort(Document):
def get_url(self): def get_url(self):
return f"{frappe.utils.get_url()}/courses/{self.course}/cohorts/{self.slug}" return f"{frappe.utils.get_url()}/courses/{self.course}/cohorts/{self.slug}"
@@ -27,11 +28,13 @@ class Cohort(Document):
return subgroups return subgroups
def _get_subgroup_counts(self, doctype, **kw): def _get_subgroup_counts(self, doctype, **kw):
rows = frappe.get_all(doctype, rows = frappe.get_all(
doctype,
filters={"cohort": self.name, **kw}, filters={"cohort": self.name, **kw},
fields=['subgroup', 'count(*) as count'], fields=["subgroup", "count(*) as count"],
group_by='subgroup') group_by="subgroup",
return {row['subgroup']: row['count'] for row in rows} )
return {row["subgroup"]: row["count"] for row in rows}
def _get_count(self, doctype, **kw): def _get_count(self, doctype, **kw):
filters = {"cohort": self.name, **kw} filters = {"cohort": self.name, **kw}
@@ -68,18 +71,9 @@ class Cohort(Document):
return name and frappe.get_doc("Cohort Mentor", name) return name and frappe.get_doc("Cohort Mentor", name)
def is_mentor(self, email): def is_mentor(self, email):
q = { q = {"doctype": "Cohort Mentor", "cohort": self.name, "email": email}
"doctype": "Cohort Mentor",
"cohort": self.name,
"email": email
}
return frappe.db.exists(q) return frappe.db.exists(q)
def is_admin(self, email): def is_admin(self, email):
q = { q = {"doctype": "Cohort Staff", "cohort": self.name, "email": email, "role": "Admin"}
"doctype": "Cohort Staff",
"cohort": self.name,
"email": email,
"role": "Admin"
}
return frappe.db.exists(q) return frappe.db.exists(q)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCohort(unittest.TestCase): class TestCohort(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Cohort Join Request', { frappe.ui.form.on("Cohort Join Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,6 +4,7 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CohortJoinRequest(Document): class CohortJoinRequest(Document):
def on_update(self): def on_update(self):
if self.status == "Accepted": if self.status == "Accepted":
@@ -16,7 +17,7 @@ class CohortJoinRequest(Document):
"cohort": self.cohort, "cohort": self.cohort,
"subgroup": self.subgroup, "subgroup": self.subgroup,
"member": self.email, "member": self.email,
"member_type": "Student" "member_type": "Student",
} }
if frappe.db.exists(q): if frappe.db.exists(q):
return return
@@ -28,7 +29,7 @@ class CohortJoinRequest(Document):
"doctype": "LMS Batch Membership", "doctype": "LMS Batch Membership",
"course": cohort.course, "course": cohort.course,
"member": self.email, "member": self.email,
"member_type": "Student" "member_type": "Student",
} }
name = frappe.db.exists(q) name = frappe.db.exists(q)
if name: if name:
@@ -45,7 +46,7 @@ class CohortJoinRequest(Document):
"subgroup": self.subgroup, "subgroup": self.subgroup,
"member": self.email, "member": self.email,
"member_type": "Student", "member_type": "Student",
"role": "Member" "role": "Member",
} }
doc = frappe.get_doc(data) doc = frappe.get_doc(data)
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCohortJoinRequest(unittest.TestCase): class TestCohortJoinRequest(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Cohort Mentor', { frappe.ui.form.on("Cohort Mentor", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,6 +4,7 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CohortMentor(Document): class CohortMentor(Document):
def get_subgroup(self): def get_subgroup(self):
return frappe.get_doc("Cohort Subgroup", self.subgroup) return frappe.get_doc("Cohort Subgroup", self.subgroup)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCohortMentor(unittest.TestCase): class TestCohortMentor(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Cohort Staff', { frappe.ui.form.on("Cohort Staff", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CohortStaff(Document): class CohortStaff(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCohortStaff(unittest.TestCase): class TestCohortStaff(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Cohort Subgroup', { frappe.ui.form.on("Cohort Subgroup", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -5,6 +5,7 @@ import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import random_string from frappe.utils import random_string
class CohortSubgroup(Document): class CohortSubgroup(Document):
def before_save(self): def before_save(self):
if not self.invite_code: if not self.invite_code:
@@ -12,49 +13,44 @@ class CohortSubgroup(Document):
def get_url(self): def get_url(self):
cohort = frappe.get_doc("Cohort", self.cohort) cohort = frappe.get_doc("Cohort", self.cohort)
return f"{frappe.utils.get_url()}/courses/{self.course}/subgroups/{cohort.slug}/{self.slug}" return (
f"{frappe.utils.get_url()}/courses/{self.course}/subgroups/{cohort.slug}/{self.slug}"
)
def get_invite_link(self): def get_invite_link(self):
cohort = frappe.get_doc("Cohort", self.cohort) cohort = frappe.get_doc("Cohort", self.cohort)
return f"{frappe.utils.get_url()}/courses/{self.course}/join/{cohort.slug}/{self.slug}/{self.invite_code}" return f"{frappe.utils.get_url()}/courses/{self.course}/join/{cohort.slug}/{self.slug}/{self.invite_code}"
def has_student(self, email): def has_student(self, email):
"""Check if given user is a student of this subgroup. """Check if given user is a student of this subgroup."""
""" q = {"doctype": "LMS Batch Membership", "subgroup": self.name, "member": email}
q = {
"doctype": "LMS Batch Membership",
"subgroup": self.name,
"member": email
}
return frappe.db.exists(q) return frappe.db.exists(q)
def has_join_request(self, email): def has_join_request(self, email):
"""Check if given user is a student of this subgroup. """Check if given user is a student of this subgroup."""
""" q = {"doctype": "Cohort Join Request", "subgroup": self.name, "email": email}
q = {
"doctype": "Cohort Join Request",
"subgroup": self.name,
"email": email
}
return frappe.db.exists(q) return frappe.db.exists(q)
def get_join_requests(self, status="Pending"): def get_join_requests(self, status="Pending"):
q = { q = {"subgroup": self.name, "status": status}
"subgroup": self.name, return frappe.get_all(
"status": status "Cohort Join Request", filters=q, fields=["*"], order_by="creation desc"
} )
return frappe.get_all("Cohort Join Request", filters=q, fields=["*"], order_by="creation desc")
def get_mentors(self): def get_mentors(self):
emails = frappe.get_all("Cohort Mentor", filters={"subgroup": self.name}, fields=["email"], pluck='email') emails = frappe.get_all(
"Cohort Mentor", filters={"subgroup": self.name}, fields=["email"], pluck="email"
)
return self._get_users(emails) return self._get_users(emails)
def get_students(self): def get_students(self):
emails = frappe.get_all("LMS Batch Membership", emails = frappe.get_all(
"LMS Batch Membership",
filters={"subgroup": self.name}, filters={"subgroup": self.name},
fields=["member"], fields=["member"],
pluck='member', pluck="member",
page_length=1000) page_length=1000,
)
return self._get_users(emails) return self._get_users(emails)
def _get_users(self, emails): def _get_users(self, emails):
@@ -62,11 +58,7 @@ class CohortSubgroup(Document):
return sorted(users, key=lambda user: user.full_name) return sorted(users, key=lambda user: user.full_name)
def is_mentor(self, email): def is_mentor(self, email):
q = { q = {"doctype": "Cohort Mentor", "subgroup": self.name, "email": email}
"doctype": "Cohort Mentor",
"subgroup": self.name,
"email": email
}
return frappe.db.exists(q) return frappe.db.exists(q)
def is_manager(self, email): def is_manager(self, email):
@@ -84,12 +76,13 @@ class CohortSubgroup(Document):
"doctype": "Cohort Mentor", "doctype": "Cohort Mentor",
"subgroup": self.name, "subgroup": self.name,
"cohort": self.cohort, "cohort": self.cohort,
"email": email "email": email,
} }
if frappe.db.exists(d): if frappe.db.exists(d):
return return
doc = frappe.get_doc(d) doc = frappe.get_doc(d)
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)
# def after_doctype_insert(): # def after_doctype_insert():
# frappe.db.add_unique("Cohort Subgroup", ("cohort", "slug")) # frappe.db.add_unique("Cohort Subgroup", ("cohort", "slug"))

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCohortSubgroup(unittest.TestCase): class TestCohortSubgroup(unittest.TestCase):
pass pass

View File

@@ -4,6 +4,7 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CohortWebPage(Document): class CohortWebPage(Document):
def get_template_html(self): def get_template_html(self):
return frappe.get_doc("Web Template", self.template).template return frappe.get_doc("Web Template", self.template).template

View File

@@ -1,14 +1,14 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Course Chapter', { frappe.ui.form.on("Course Chapter", {
onload: function (frm) { onload: function (frm) {
frm.set_query("lesson", "lessons", function () { frm.set_query("lesson", "lessons", function () {
return { return {
filters: { filters: {
"chapter": frm.doc.name, chapter: frm.doc.name,
} },
}; };
}); });
} },
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CourseChapter(Document): class CourseChapter(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCourseChapter(unittest.TestCase): class TestCourseChapter(unittest.TestCase):
pass pass

View File

@@ -1,14 +1,14 @@
// Copyright (c) 2022, Frappe and contributors // Copyright (c) 2022, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Course Evaluator', { frappe.ui.form.on("Course Evaluator", {
onload: (frm) => { onload: (frm) => {
frm.set_query('evaluator', function(doc) { frm.set_query("evaluator", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
} },
}); });

View File

@@ -5,8 +5,8 @@ import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
class CourseEvaluator(Document):
class CourseEvaluator(Document):
def validate(self): def validate(self):
self.validate_time_slots() self.validate_time_slots()
@@ -18,7 +18,9 @@ class CourseEvaluator(Document):
self.validate_overlaps(schedule) self.validate_overlaps(schedule)
def validate_overlaps(self, schedule): def validate_overlaps(self, schedule):
same_day_slots = list(filter(lambda x: x.day == schedule.day and x.name != schedule.name , self.schedule)) same_day_slots = list(
filter(lambda x: x.day == schedule.day and x.name != schedule.name, self.schedule)
)
overlap = False overlap = False
for slot in same_day_slots: for slot in same_day_slots:
@@ -32,15 +34,20 @@ class CourseEvaluator(Document):
if overlap: if overlap:
frappe.throw(_("Slot Times are overlapping for some schedules.")) frappe.throw(_("Slot Times are overlapping for some schedules."))
@frappe.whitelist() @frappe.whitelist()
def get_schedule(course, date): def get_schedule(course, date):
evaluator = frappe.db.get_value("LMS Course", course, "evaluator") evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
all_slots = frappe.get_all("Evaluator Schedule", all_slots = frappe.get_all(
"Evaluator Schedule",
filters={"parent": evaluator}, filters={"parent": evaluator},
fields = ["day", "start_time", "end_time"]) fields=["day", "start_time", "end_time"],
booked_slots = frappe.get_all("LMS Certificate Request", )
booked_slots = frappe.get_all(
"LMS Certificate Request",
filters={"evaluator": evaluator, "date": date}, filters={"evaluator": evaluator, "date": date},
fields = ["start_time"]) fields=["start_time"],
)
for slot in booked_slots: for slot in booked_slots:
same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots)) same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots))

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class CourseInstructor(Document): class CourseInstructor(Document):
pass pass

View File

@@ -1,17 +1,21 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Course Lesson', { frappe.ui.form.on("Course Lesson", {
setup: function (frm) { setup: function (frm) {
frm.trigger('setup_help'); frm.trigger("setup_help");
}, },
setup_help(frm) { setup_help(frm) {
let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`; let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`;
let exercise_link = `<a href="/app/exercise"> ${__("Exercise List")} </a>`; let exercise_link = `<a href="/app/exercise"> ${__(
"Exercise List"
)} </a>`;
let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`; let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`;
frm.get_field('help').html(` frm.get_field("help").html(`
<p>${__("You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same.")}</p> <p>${__(
"You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same."
)}</p>
<table class="table"> <table class="table">
<tr style="background-color: var(--fg-hover-color); font-weight: bold"> <tr style="background-color: var(--fg-hover-color); font-weight: bold">
<th style="width: 20%;"> <th style="width: 20%;">
@@ -33,17 +37,23 @@ frappe.ui.form.on('Course Lesson', {
</td> </td>
<td> <td>
<span> <span>
${ __("Copy and paste the syntax in the editor. Replace 'embed_src' with the embed source that YouTube provides. To get the source, follow the steps mentioned below.") } ${__(
"Copy and paste the syntax in the editor. Replace 'embed_src' with the embed source that YouTube provides. To get the source, follow the steps mentioned below."
)}
</span> </span>
<ul class="p-4"> <ul class="p-4">
<li> <li>
${__("Upload the video on youtube.")} ${__("Upload the video on youtube.")}
</li> </li>
<li> <li>
${ __("When you share a youtube video, it shows an option called Embed.") } ${__(
"When you share a youtube video, it shows an option called Embed."
)}
</li> </li>
<li> <li>
${ __("On clicking it, it provides an iframe. Copy the source (src) of the iframe and paste it here.") } ${__(
"On clicking it, it provides an iframe. Copy the source (src) of the iframe and paste it here."
)}
</li> </li>
</ul> </ul>
</td> </td>
@@ -56,7 +66,10 @@ frappe.ui.form.on('Course Lesson', {
{{ Quiz("lms_quiz_id") }} {{ Quiz("lms_quiz_id") }}
</td> </td>
<td> <td>
${ __("Copy and paste the syntax in the editor. Replace 'lms_quiz_id' with the ID of the Quiz you want to add. You can get the ID of the quiz from the {0}.", [quiz_link]) } ${__(
"Copy and paste the syntax in the editor. Replace 'lms_quiz_id' with the ID of the Quiz you want to add. You can get the ID of the quiz from the {0}.",
[quiz_link]
)}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -67,7 +80,10 @@ frappe.ui.form.on('Course Lesson', {
{{ Video("url_of_source") }} {{ Video("url_of_source") }}
</td> </td>
<td> <td>
${ __("Upload a video from your local machine to the {0}. Copy and paste this syntax in the editor. Replace 'url_of_source' with the File URL field of the document you created in the File DocType.", [file_link]) } ${__(
"Upload a video from your local machine to the {0}. Copy and paste this syntax in the editor. Replace 'url_of_source' with the File URL field of the document you created in the File DocType.",
[file_link]
)}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -78,7 +94,10 @@ frappe.ui.form.on('Course Lesson', {
{{ Exercise("exercise_id") }} {{ Exercise("exercise_id") }}
</td> </td>
<td> <td>
${ __("Copy and paste the syntax in the editor. Replace 'exercise_id' with the ID of the Exercise you want to add. You can get the ID of the exercise from the {0}.", [exercise_link]) } ${__(
"Copy and paste the syntax in the editor. Replace 'exercise_id' with the ID of the Exercise you want to add. You can get the ID of the exercise from the {0}.",
[exercise_link]
)}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -125,5 +144,5 @@ frappe.ui.form.on('Course Lesson', {
</tr> </tr>
</table> </table>
`); `);
} },
}); });

View File

@@ -1,37 +1,31 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from ...md import find_macros
from lms.lms.utils import get_course_progress, get_lesson_url from lms.lms.utils import get_course_progress, get_lesson_url
from ...md import find_macros
class CourseLesson(Document): class CourseLesson(Document):
def validate(self): def validate(self):
# self.check_and_create_folder() # self.check_and_create_folder()
self.validate_quiz_id() self.validate_quiz_id()
def validate_quiz_id(self): def validate_quiz_id(self):
if self.quiz_id and not frappe.db.exists("LMS Quiz", self.quiz_id): if self.quiz_id and not frappe.db.exists("LMS Quiz", self.quiz_id):
frappe.throw(_("Invalid Quiz ID")) frappe.throw(_("Invalid Quiz ID"))
def on_update(self): def on_update(self):
dynamic_documents = ["Exercise", "Quiz"] dynamic_documents = ["Exercise", "Quiz"]
for section in dynamic_documents: for section in dynamic_documents:
self.update_lesson_name_in_document(section) self.update_lesson_name_in_document(section)
def update_lesson_name_in_document(self, section): def update_lesson_name_in_document(self, section):
doctype_map= { doctype_map = {"Exercise": "Exercise", "Quiz": "LMS Quiz"}
"Exercise": "Exercise",
"Quiz": "LMS Quiz"
}
macros = find_macros(self.body) macros = find_macros(self.body)
documents = [value for name, value in macros if name == section] documents = [value for name, value in macros if name == section]
index = 1 index = 1
@@ -43,12 +37,13 @@ class CourseLesson(Document):
index += 1 index += 1
self.update_orphan_documents(doctype_map[section], documents) self.update_orphan_documents(doctype_map[section], documents)
def update_orphan_documents(self, doctype, documents): def update_orphan_documents(self, doctype, documents):
"""Updates the documents that were previously part of this lesson, """Updates the documents that were previously part of this lesson,
but not any more. but not any more.
""" """
linked_documents = {row['name'] for row in frappe.get_all(doctype, {"lesson": self.name})} linked_documents = {
row["name"] for row in frappe.get_all(doctype, {"lesson": self.name})
}
active_documents = set(documents) active_documents = set(documents)
orphan_documents = linked_documents - active_documents orphan_documents = linked_documents - active_documents
for name in orphan_documents: for name in orphan_documents:
@@ -58,18 +53,16 @@ class CourseLesson(Document):
ex.index_label = "" ex.index_label = ""
ex.save() ex.save()
def check_and_create_folder(self): def check_and_create_folder(self):
args = { args = {
"doctype": "File", "doctype": "File",
"is_folder": True, "is_folder": True,
"file_name": f"{self.name} {self.course}" "file_name": f"{self.name} {self.course}",
} }
if not frappe.db.exists(args): if not frappe.db.exists(args):
folder = frappe.get_doc(args) folder = frappe.get_doc(args)
folder.save(ignore_permissions=True) folder.save(ignore_permissions=True)
def get_exercises(self): def get_exercises(self):
if not self.body: if not self.body:
return [] return []
@@ -79,7 +72,9 @@ class CourseLesson(Document):
return [frappe.get_doc("Exercise", name) for name in exercises] return [frappe.get_doc("Exercise", name) for name in exercises]
def get_progress(self): def get_progress(self):
return frappe.db.get_value("LMS Course Progress", {"lesson": self.name, "owner": frappe.session.user}, "status") return frappe.db.get_value(
"LMS Course Progress", {"lesson": self.name, "owner": frappe.session.user}, "status"
)
def get_slugified_class(self): def get_slugified_class(self):
if self.get_progress(): if self.get_progress():
@@ -89,31 +84,30 @@ class CourseLesson(Document):
@frappe.whitelist() @frappe.whitelist()
def save_progress(lesson, course, status): def save_progress(lesson, course, status):
membership = frappe.db.exists("LMS Batch Membership", { membership = frappe.db.exists(
"member": frappe.session.user, "LMS Batch Membership", {"member": frappe.session.user, "course": course}
"course": course )
})
if not membership: if not membership:
return return
if frappe.db.exists("LMS Course Progress", { if frappe.db.exists(
"lesson": lesson, "LMS Course Progress",
"owner": frappe.session.user, {"lesson": lesson, "owner": frappe.session.user, "course": course},
"course": course ):
}): doc = frappe.get_doc(
doc = frappe.get_doc("LMS Course Progress", { "LMS Course Progress",
"lesson": lesson, {"lesson": lesson, "owner": frappe.session.user, "course": course},
"owner": frappe.session.user, )
"course": course
})
doc.status = status doc.status = status
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
else: else:
frappe.get_doc({ frappe.get_doc(
{
"doctype": "LMS Course Progress", "doctype": "LMS Course Progress",
"lesson": lesson, "lesson": lesson,
"status": status, "status": status,
}).save(ignore_permissions=True) }
).save(ignore_permissions=True)
progress = get_course_progress(course) progress = get_course_progress(course)
frappe.db.set_value("LMS Batch Membership", membership, "progress", progress) frappe.db.set_value("LMS Batch Membership", membership, "progress", progress)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestCourseLesson(unittest.TestCase): class TestCourseLesson(unittest.TestCase):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class EducationDetail(Document): class EducationDetail(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class EvaluatorSchedule(Document): class EvaluatorSchedule(Document):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Exercise', { frappe.ui.form.on("Exercise", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -3,31 +3,30 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from lms.lms.utils import get_membership from lms.lms.utils import get_membership
class Exercise(Document): class Exercise(Document):
def get_user_submission(self): def get_user_submission(self):
"""Returns the latest submission for this user. """Returns the latest submission for this user."""
"""
user = frappe.session.user user = frappe.session.user
if not user or user == "Guest": if not user or user == "Guest":
return return
result = frappe.get_all('Exercise Submission', result = frappe.get_all(
"Exercise Submission",
fields="*", fields="*",
filters={ filters={"owner": user, "exercise": self.name},
"owner": user,
"exercise": self.name
},
order_by="creation desc", order_by="creation desc",
page_length=1) page_length=1,
)
if result: if result:
return result[0] return result[0]
def submit(self, code): def submit(self, code):
"""Submits the given code as solution to exercise. """Submits the given code as solution to exercise."""
"""
user = frappe.session.user user = frappe.session.user
if not user or user == "Guest": if not user or user == "Guest":
return return
@@ -46,8 +45,8 @@ class Exercise(Document):
lesson=self.lesson, lesson=self.lesson,
batch=member.batch, batch=member.batch,
solution=code, solution=code,
member=member.name) member=member.name,
)
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)
return doc return doc

View File

@@ -1,31 +1,35 @@
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
import frappe
import unittest import unittest
import frappe
from lms.lms.doctype.lms_course.test_lms_course import new_course from lms.lms.doctype.lms_course.test_lms_course import new_course
class TestExercise(unittest.TestCase):
class TestExercise(unittest.TestCase):
def new_exercise(self): def new_exercise(self):
course = new_course("Test Course") course = new_course("Test Course")
member = frappe.get_doc({ member = frappe.get_doc(
{
"doctype": "LMS Batch Membership", "doctype": "LMS Batch Membership",
"course": course.name, "course": course.name,
"member": frappe.session.user "member": frappe.session.user,
}) }
)
member.insert() member.insert()
e = frappe.get_doc({ e = frappe.get_doc(
{
"doctype": "Exercise", "doctype": "Exercise",
"name": "test-problem", "name": "test-problem",
"course": course.name, "course": course.name,
"title": "Test Problem", "title": "Test Problem",
"description": "draw a circle", "description": "draw a circle",
"code": "# draw a single cicle", "code": "# draw a single cicle",
"answer": ( "answer": ("# draw a single circle\n" + "circle(100, 100, 50)"),
"# draw a single circle\n" + }
"circle(100, 100, 50)") )
})
e.insert() e.insert()
return e return e
@@ -45,6 +49,6 @@ class TestExercise(unittest.TestCase):
assert user_submission.name == submission.name assert user_submission.name == submission.name
def tearDown(self): def tearDown(self):
frappe.db.sql('delete from `tabLMS Batch Membership`') frappe.db.sql("delete from `tabLMS Batch Membership`")
frappe.db.sql('delete from `tabExercise Submission`') frappe.db.sql("delete from `tabExercise Submission`")
frappe.db.sql('delete from `tabExercise`') frappe.db.sql("delete from `tabExercise`")

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Exercise Latest Submission', { frappe.ui.form.on("Exercise Latest Submission", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class ExerciseLatestSubmission(Document): class ExerciseLatestSubmission(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestExerciseLatestSubmission(unittest.TestCase): class TestExerciseLatestSubmission(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Exercise Submission', { frappe.ui.form.on("Exercise Submission", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,21 +4,26 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class ExerciseSubmission(Document): class ExerciseSubmission(Document):
def on_update(self): def on_update(self):
self.update_latest_submission() self.update_latest_submission()
def update_latest_submission(self): def update_latest_submission(self):
names = frappe.get_all("Exercise Latest Submission", {"exercise": self.exercise, "member": self.member}) names = frappe.get_all(
"Exercise Latest Submission", {"exercise": self.exercise, "member": self.member}
)
if names: if names:
doc = frappe.get_doc("Exercise Latest Submission", names[0]) doc = frappe.get_doc("Exercise Latest Submission", names[0])
doc.latest_submission = self.name doc.latest_submission = self.name
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
else: else:
doc = frappe.get_doc({ doc = frappe.get_doc(
{
"doctype": "Exercise Latest Submission", "doctype": "Exercise Latest Submission",
"exercise": self.exercise, "exercise": self.exercise,
"member": self.member, "member": self.member,
"latest_submission": self.name "latest_submission": self.name,
}) }
)
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestExerciseSubmission(unittest.TestCase): class TestExerciseSubmission(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Function', { frappe.ui.form.on("Function", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Function(Document): class Function(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestFunction(unittest.TestCase): class TestFunction(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Industry', { frappe.ui.form.on("Industry", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Industry(Document): class Industry(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestIndustry(unittest.TestCase): class TestIndustry(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Invite Request', { frappe.ui.form.on("Invite Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals import json
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
import json
from frappe.utils.password import get_decrypted_password from frappe.utils.password import get_decrypted_password
class InviteRequest(Document): class InviteRequest(Document):
def on_update(self): def on_update(self):
if self.has_value_changed("status") and self.status == "Approved": if self.has_value_changed("status") and self.status == "Approved":
@@ -16,7 +16,8 @@ class InviteRequest(Document):
def create_user(self, password): def create_user(self, password):
full_name_split = self.full_name.split(" ") full_name_split = self.full_name.split(" ")
user = frappe.get_doc({ user = frappe.get_doc(
{
"doctype": "User", "doctype": "User",
"email": self.signup_email, "email": self.signup_email,
"first_name": full_name_split[0], "first_name": full_name_split[0],
@@ -24,8 +25,9 @@ class InviteRequest(Document):
"username": self.username, "username": self.username,
"send_welcome_email": 0, "send_welcome_email": 0,
"user_type": "Website User", "user_type": "Website User",
"new_password": password "new_password": password,
}) }
)
user.save(ignore_permissions=True) user.save(ignore_permissions=True)
return user return user
@@ -35,9 +37,9 @@ class InviteRequest(Document):
args = { args = {
"full_name": self.full_name, "full_name": self.full_name,
"signup_form_link": "/new-sign-up?invite_code={0}".format(self.name), "signup_form_link": f"/new-sign-up?invite_code={self.name}",
"site_name": site_name, "site_name": site_name,
"site_url": frappe.utils.get_url() "site_url": frappe.utils.get_url(),
} }
frappe.sendmail( frappe.sendmail(
recipients=self.invite_email, recipients=self.invite_email,
@@ -45,7 +47,9 @@ class InviteRequest(Document):
header=[subject, "green"], header=[subject, "green"],
template="lms_invite_request_approved", template="lms_invite_request_approved",
args=args, args=args,
now=True) now=True,
)
@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
def create_invite_request(invite_email): def create_invite_request(invite_email):
@@ -59,11 +63,9 @@ def create_invite_request(invite_email):
if frappe.db.exists("Invite Request", {"invite_email": invite_email}): if frappe.db.exists("Invite Request", {"invite_email": invite_email}):
return "invite" return "invite"
frappe.get_doc({ frappe.get_doc(
"doctype": "Invite Request", {"doctype": "Invite Request", "invite_email": invite_email, "status": "Approved"}
"invite_email": invite_email, ).save(ignore_permissions=True)
"status": "Approved"
}).save(ignore_permissions=True)
return "OK" return "OK"

View File

@@ -1,23 +1,26 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # 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 import unittest
class TestInviteRequest(unittest.TestCase): import frappe
from lms.lms.doctype.invite_request.invite_request import (
create_invite_request, update_invite)
class TestInviteRequest(unittest.TestCase):
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
create_invite_request("test_invite@example.com") create_invite_request("test_invite@example.com")
def test_create_invite_request(self): def test_create_invite_request(self):
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}): if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
invite = frappe.db.get_value("Invite Request", invite = frappe.db.get_value(
"Invite Request",
filters={"invite_email": "test_invite@example.com"}, filters={"invite_email": "test_invite@example.com"},
fieldname=["invite_email", "status", "signup_email"], fieldname=["invite_email", "status", "signup_email"],
as_dict=True) as_dict=True,
)
self.assertEqual(invite.status, "Approved") self.assertEqual(invite.status, "Approved")
self.assertEqual(invite.signup_email, None) self.assertEqual(invite.signup_email, None)
@@ -29,23 +32,38 @@ class TestInviteRequest(unittest.TestCase):
"username": "test_invite", "username": "test_invite",
"full_name": "Test Invite", "full_name": "Test Invite",
"password": "Test@invite", "password": "Test@invite",
"invite_code": frappe.db.get_value("Invite Request", {"invite_email": "test_invite@example.com"}, "name") "invite_code": frappe.db.get_value(
"Invite Request", {"invite_email": "test_invite@example.com"}, "name"
),
} }
update_invite(data) update_invite(data)
invite = frappe.db.get_value("Invite Request", invite = frappe.db.get_value(
"Invite Request",
filters={"invite_email": "test_invite@example.com"}, filters={"invite_email": "test_invite@example.com"},
fieldname=["invite_email", "status", "signup_email", "full_name", "username", "invite_code", "name"], fieldname=[
as_dict=True) "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.signup_email, "test_invite@example.com")
self.assertEqual(invite.full_name, "Test Invite") self.assertEqual(invite.full_name, "Test Invite")
self.assertEqual(invite.username, "test_invite") self.assertEqual(invite.username, "test_invite")
self.assertEqual(invite.invite_code, invite.name) self.assertEqual(invite.invite_code, invite.name)
self.assertEqual(invite.status, "Registered") self.assertEqual(invite.status, "Registered")
user = frappe.db.get_value("User", "test_invite@example.com", user = frappe.db.get_value(
"User",
"test_invite@example.com",
fieldname=["first_name", "username", "send_welcome_email", "user_type"], fieldname=["first_name", "username", "send_welcome_email", "user_type"],
as_dict=True) as_dict=True,
)
self.assertTrue(user) self.assertTrue(user)
self.assertEqual(user.first_name, invite.full_name.split(" ")[0]) self.assertEqual(user.first_name, invite.full_name.split(" ")[0])
self.assertEqual(user.username, invite.username) self.assertEqual(user.username, invite.username)
@@ -57,6 +75,8 @@ class TestInviteRequest(unittest.TestCase):
if frappe.db.exists("User", "test_invite@example.com"): if frappe.db.exists("User", "test_invite@example.com"):
frappe.delete_doc("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"}) invite_request = frappe.db.exists(
"Invite Request", {"invite_email": "test_invite@example.com"}
)
if invite_request: if invite_request:
frappe.delete_doc("Invite Request", invite_request) frappe.delete_doc("Invite Request", invite_request)

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, Frappe and contributors // Copyright (c) 2021, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Lesson Assignment', { frappe.ui.form.on("Lesson Assignment", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,19 +2,24 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.model.document import Document
class LessonAssignment(Document): class LessonAssignment(Document):
def validate(self): def validate(self):
self.validate_duplicates() self.validate_duplicates()
def validate_duplicates(self): def validate_duplicates(self):
if frappe.db.exists("Lesson Assignment", {"lesson": self.lesson, "member": self.member}): if frappe.db.exists(
"Lesson Assignment", {"lesson": self.lesson, "member": self.member}
):
lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title") lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title")
frappe.throw(_("Assignment for Lesson {0} by {1} already exists.").format(lesson_title, self.member_name)) frappe.throw(
_("Assignment for Lesson {0} by {1} already exists.").format(
lesson_title, self.member_name
)
)
@frappe.whitelist() @frappe.whitelist()
@@ -22,7 +27,7 @@ def upload_assignment(assignment, lesson):
args = { args = {
"doctype": "Lesson Assignment", "doctype": "Lesson Assignment",
"lesson": lesson, "lesson": lesson,
"member": frappe.session.user "member": frappe.session.user,
} }
if frappe.db.exists(args): if frappe.db.exists(args):
del args["doctype"] del args["doctype"]
@@ -35,15 +40,13 @@ def upload_assignment(assignment, lesson):
@frappe.whitelist() @frappe.whitelist()
def get_assignment(lesson): def get_assignment(lesson):
assignment = frappe.db.get_value("Lesson Assignment", { assignment = frappe.db.get_value(
"lesson": lesson, "Lesson Assignment",
"member": frappe.session.user {"lesson": lesson, "member": frappe.session.user},
}, ["lesson", "member", "assignment"], ["lesson", "member", "assignment"],
as_dict=True) as_dict=True,
assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name") )
assignment.file_name = frappe.db.get_value(
"File", {"file_url": assignment.assignment}, "file_name"
)
return assignment return assignment

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestLessonAssignment(unittest.TestCase): class TestLessonAssignment(unittest.TestCase):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class LessonReference(Document): class LessonReference(Document):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Batch', { frappe.ui.form.on("LMS Batch", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document
from frappe import _ from frappe import _
from lms.lms.doctype.lms_batch_membership.lms_batch_membership import create_membership from frappe.model.document import Document
from lms.lms.doctype.lms_batch_membership.lms_batch_membership import \
create_membership
from lms.lms.utils import is_mentor from lms.lms.utils import is_mentor
class LMSBatch(Document): class LMSBatch(Document):
def validate(self): def validate(self):
pass pass
@@ -28,49 +29,44 @@ class LMSBatch(Document):
If member_type is specified, checks if the person is a Student/Mentor. If member_type is specified, checks if the person is a Student/Mentor.
""" """
filters = { filters = {"batch": self.name, "member": email}
"batch": self.name,
"member": email
}
if member_type: if member_type:
filters['member_type'] = member_type filters["member_type"] = member_type
return frappe.db.exists("LMS Batch Membership", filters) return frappe.db.exists("LMS Batch Membership", filters)
def get_membership(self, email): def get_membership(self, email):
"""Returns the membership document of given user. """Returns the membership document of given user."""
"""
name = frappe.get_value( name = frappe.get_value(
doctype="LMS Batch Membership", doctype="LMS Batch Membership",
filters={ filters={"batch": self.name, "member": email},
"batch": self.name, fieldname="name",
"member": email )
},
fieldname="name")
return frappe.get_doc("LMS Batch Membership", name) return frappe.get_doc("LMS Batch Membership", name)
def get_current_lesson(self, user): def get_current_lesson(self, user):
"""Returns the name of the current lesson for the given user. """Returns the name of the current lesson for the given user."""
"""
membership = self.get_membership(user) membership = self.get_membership(user)
return membership and membership.current_lesson return membership and membership.current_lesson
@frappe.whitelist() @frappe.whitelist()
def save_message(message, batch): def save_message(message, batch):
doc = frappe.get_doc({ doc = frappe.get_doc(
{
"doctype": "LMS Message", "doctype": "LMS Message",
"batch": batch, "batch": batch,
"author": frappe.session.user, "author": frappe.session.user,
"message": message "message": message,
}) }
)
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
def switch_batch(course_name, email, batch_name): def switch_batch(course_name, email, batch_name):
"""Switches the user from the current batch of the course to a new batch. """Switches the user from the current batch of the course to a new batch."""
"""
membership = frappe.get_last_doc( membership = frappe.get_last_doc(
"LMS Batch Membership", "LMS Batch Membership", filters={"course": course_name, "member": email}
filters={"course": course_name, "member": email}) )
batch = frappe.get_doc("LMS Batch", batch_name) batch = frappe.get_doc("LMS Batch", batch_name)
if not batch: if not batch:
@@ -90,11 +86,8 @@ def switch_batch(course_name, email, batch_name):
membership.save() membership.save()
# update exercise submissions # update exercise submissions
filters = { filters = {"owner": email, "batch": old_batch.name}
"owner": email, for name in frappe.db.get_all("Exercise Submission", filters=filters, pluck="name"):
"batch": old_batch.name
}
for name in frappe.db.get_all("Exercise Submission", filters=filters, pluck='name'):
doc = frappe.get_doc("Exercise Submission", name) doc = frappe.get_doc("Exercise Submission", name)
print("updating exercise submission", name) print("updating exercise submission", name)
doc.batch = batch_name doc.batch = batch_name

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
# import frappe # import frappe
import unittest import unittest
class TestLMSBatch(unittest.TestCase): class TestLMSBatch(unittest.TestCase):
pass pass

View File

@@ -1,14 +1,14 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Batch Membership', { frappe.ui.form.on("LMS Batch Membership", {
onload: function (frm) { onload: function (frm) {
frm.set_query('member', function(doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
} },
}); });

View File

@@ -1,39 +1,35 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.model.document import Document
class LMSBatchMembership(Document): class LMSBatchMembership(Document):
def validate(self): def validate(self):
self.validate_membership_in_same_batch() self.validate_membership_in_same_batch()
self.validate_membership_in_different_batch_same_course() self.validate_membership_in_different_batch_same_course()
def validate_membership_in_same_batch(self): def validate_membership_in_same_batch(self):
filters={ filters = {"member": self.member, "course": self.course, "name": ["!=", self.name]}
"member": self.member,
"course": self.course,
"name": ["!=", self.name]
}
if self.batch: if self.batch:
filters["batch"] = self.batch filters["batch"] = self.batch
previous_membership = frappe.db.get_value("LMS Batch Membership", previous_membership = frappe.db.get_value(
filters, "LMS Batch Membership", filters, fieldname=["member_type", "member"], as_dict=1
fieldname=["member_type","member"], )
as_dict=1)
if previous_membership: if previous_membership:
member_name = frappe.db.get_value("User", self.member, "full_name") member_name = frappe.db.get_value("User", self.member, "full_name")
course_title = frappe.db.get_value("LMS Course", self.course, "title") course_title = frappe.db.get_value("LMS Course", self.course, "title")
frappe.throw(_("{0} is already a {1} of the course {2}").format(member_name, previous_membership.member_type, course_title)) frappe.throw(
_("{0} is already a {1} of the course {2}").format(
member_name, previous_membership.member_type, course_title
)
)
def validate_membership_in_different_batch_same_course(self): def validate_membership_in_different_batch_same_course(self):
"""Ensures that a studnet is only part of one batch. """Ensures that a studnet is only part of one batch."""
"""
# nothing to worry if the member is not a student # nothing to worry if the member is not a student
if self.member_type != "Student": if self.member_type != "Student":
return return
@@ -45,34 +41,50 @@ class LMSBatchMembership(Document):
"member": self.member, "member": self.member,
"name": ["!=", self.name], "name": ["!=", self.name],
"member_type": "Student", "member_type": "Student",
"course": self.course "course": self.course,
}, },
fields=["batch", "member_type", "name"] fields=["batch", "member_type", "name"],
) )
if memberships: if memberships:
membership = memberships[0] membership = memberships[0]
member_name = frappe.db.get_value("User", self.member, "full_name") member_name = frappe.db.get_value("User", self.member, "full_name")
frappe.throw(_("{0} is already a Student of {1} course through {2} batch").format(member_name, course, membership.batch)) frappe.throw(
_("{0} is already a Student of {1} course through {2} batch").format(
member_name, course, membership.batch
)
)
@frappe.whitelist() @frappe.whitelist()
def create_membership(course, batch=None, member=None, member_type="Student", role="Member"): def create_membership(
frappe.get_doc({ course, batch=None, member=None, member_type="Student", role="Member"
):
frappe.get_doc(
{
"doctype": "LMS Batch Membership", "doctype": "LMS Batch Membership",
"batch": batch, "batch": batch,
"course": course, "course": course,
"role": role, "role": role,
"member_type": member_type, "member_type": member_type,
"member": member or frappe.session.user "member": member or frappe.session.user,
}).save(ignore_permissions=True) }
).save(ignore_permissions=True)
return "OK" return "OK"
@frappe.whitelist() @frappe.whitelist()
def update_current_membership(batch, course, member): def update_current_membership(batch, course, member):
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": course}) all_memberships = frappe.get_all(
"LMS Batch Membership", {"member": member, "course": course}
)
for membership in all_memberships: for membership in all_memberships:
frappe.db.set_value("LMS Batch Membership", membership.name, "is_current", 0) frappe.db.set_value("LMS Batch Membership", membership.name, "is_current", 0)
current_membership = frappe.get_all("LMS Batch Membership", {"batch": batch, "member": member}) current_membership = frappe.get_all(
"LMS Batch Membership", {"batch": batch, "member": member}
)
if len(current_membership): if len(current_membership):
frappe.db.set_value("LMS Batch Membership", current_membership[0].name, "is_current", 1) frappe.db.set_value(
"LMS Batch Membership", current_membership[0].name, "is_current", 1
)

View File

@@ -1,17 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
import unittest
import frappe import frappe
import unittest
from lms.lms.doctype.lms_course.test_lms_course import new_user, new_course from lms.lms.doctype.lms_course.test_lms_course import new_course, new_user
class TestLMSBatchMembership(unittest.TestCase): class TestLMSBatchMembership(unittest.TestCase):
def setUp(self): def setUp(self):
frappe.db.sql("DELETE FROM `tabLMS Batch Membership`") frappe.db.sql("DELETE FROM `tabLMS Batch Membership`")
frappe.db.sql("DELETE FROM `tabLMS Batch`") frappe.db.sql("DELETE FROM `tabLMS Batch`")
frappe.db.sql('delete from `tabLMS Course Mentor Mapping`') frappe.db.sql("delete from `tabLMS Course Mentor Mapping`")
frappe.db.sql("DELETE FROM `tabUser` where email like '%@test.com'") frappe.db.sql("DELETE FROM `tabUser` where email like '%@test.com'")
def new_course_batch(self): def new_course_batch(self):
@@ -23,24 +24,28 @@ class TestLMSBatchMembership(unittest.TestCase):
frappe.session.user = "mentor@test.com" frappe.session.user = "mentor@test.com"
batch = frappe.get_doc({ batch = frappe.get_doc(
{
"doctype": "LMS Batch", "doctype": "LMS Batch",
"name": "test-batch", "name": "test-batch",
"title": "Test Batch", "title": "Test Batch",
"course": course.name "course": course.name,
}) }
)
batch.insert(ignore_permissions=True) batch.insert(ignore_permissions=True)
frappe.session.user = "Administrator" frappe.session.user = "Administrator"
return course, batch return course, batch
def add_membership(self, batch_name, member_name, member_type="Student"): def add_membership(self, batch_name, member_name, member_type="Student"):
doc = frappe.get_doc({ doc = frappe.get_doc(
{
"doctype": "LMS Batch Membership", "doctype": "LMS Batch Membership",
"batch": batch_name, "batch": batch_name,
"member": member_name, "member": member_name,
"member_type": member_type "member_type": member_type,
}) }
)
doc.insert() doc.insert()
return doc return doc

View File

@@ -1,17 +1,21 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Certificate', { frappe.ui.form.on("LMS Certificate", {
onload: (frm) => { onload: (frm) => {
frm.set_query("member", function (doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
}, },
refresh: (frm) => { refresh: (frm) => {
if (frm.doc.name) frm.add_web_link(`/courses/${frm.doc.course}/${frm.doc.name}`, 'See on Website') if (frm.doc.name)
} frm.add_web_link(
`/courses/${frm.doc.course}/${frm.doc.name}`,
"See on Website"
);
},
}); });

View File

@@ -2,23 +2,26 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe.model.document import Document
from frappe.utils import nowdate, add_years
from frappe import _ from frappe import _
from frappe.model.document import Document
from frappe.utils import add_years, nowdate
from frappe.utils.pdf import get_pdf from frappe.utils.pdf import get_pdf
from lms.lms.utils import is_certified from lms.lms.utils import is_certified
class LMSCertificate(Document):
class LMSCertificate(Document):
def before_insert(self): def before_insert(self):
certificates = frappe.get_all("LMS Certificate", { certificates = frappe.get_all(
"member": self.member, "LMS Certificate", {"member": self.member, "course": self.course}
"course": self.course )
})
if len(certificates): if len(certificates):
full_name = frappe.db.get_value("User", self.member, "full_name") full_name = frappe.db.get_value("User", self.member, "full_name")
course_name = frappe.db.get_value("LMS Course", self.course, "title") course_name = frappe.db.get_value("LMS Course", self.course, "title")
frappe.throw(_("{0} is already certified for the course {1}").format(full_name, course_name)) frappe.throw(
_("{0} is already certified for the course {1}").format(full_name, course_name)
)
@frappe.whitelist() @frappe.whitelist()
def create_certificate(course): def create_certificate(course):
@@ -33,16 +36,19 @@ def create_certificate(course):
if expires_after_yrs: if expires_after_yrs:
expiry_date = add_years(nowdate(), expires_after_yrs) expiry_date = add_years(nowdate(), expires_after_yrs)
certificate = frappe.get_doc({ certificate = frappe.get_doc(
{
"doctype": "LMS Certificate", "doctype": "LMS Certificate",
"member": frappe.session.user, "member": frappe.session.user,
"course": course, "course": course,
"issue_date": nowdate(), "issue_date": nowdate(),
"expiry_date": expiry_date "expiry_date": expiry_date,
}) }
)
certificate.save(ignore_permissions=True) certificate.save(ignore_permissions=True)
return certificate return certificate
@frappe.whitelist() @frappe.whitelist()
def get_certificate_pdf(html): def get_certificate_pdf(html):
frappe.local.response.filename = "certificate.pdf" frappe.local.response.filename = "certificate.pdf"

View File

@@ -1,19 +1,18 @@
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
import frappe
import unittest import unittest
from lms.lms.doctype.lms_course.test_lms_course import new_course
import frappe
from frappe.utils import add_years, cint, nowdate
from lms.lms.doctype.lms_certificate.lms_certificate import create_certificate from lms.lms.doctype.lms_certificate.lms_certificate import create_certificate
from frappe.utils import nowdate, add_years, cint from lms.lms.doctype.lms_course.test_lms_course import new_course
class TestLMSCertificate(unittest.TestCase): class TestLMSCertificate(unittest.TestCase):
def test_certificate_creation(self): def test_certificate_creation(self):
course = new_course("Test Certificate", { course = new_course("Test Certificate", {"enable_certification": 1, "expiry": 2})
"enable_certification": 1,
"expiry": 2
})
certificate = create_certificate(course.name) certificate = create_certificate(course.name)
self.assertEqual(certificate.member, "Administrator") self.assertEqual(certificate.member, "Administrator")

View File

@@ -1,13 +1,13 @@
// Copyright (c) 2022, Frappe and contributors // Copyright (c) 2022, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Certificate Evaluation', { frappe.ui.form.on("LMS Certificate Evaluation", {
refresh: function (frm) { refresh: function (frm) {
if (frm.doc.status == "Pass") { if (frm.doc.status == "Pass") {
frm.add_custom_button(__("Create LMS Certificate"), () => { frm.add_custom_button(__("Create LMS Certificate"), () => {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate", method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate",
frm: frm frm: frm,
}); });
}); });
} }
@@ -17,18 +17,18 @@ frappe.ui.form.on('LMS Certificate Evaluation', {
frm.set_query("course", function (doc) { frm.set_query("course", function (doc) {
return { return {
filters: { filters: {
"enable_certification": true, enable_certification: true,
"grant_certificate_after": "Evaluation" grant_certificate_after: "Evaluation",
} },
}; };
}); });
frm.set_query('member', function(doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
} },
}); });

View File

@@ -5,14 +5,17 @@ import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
class LMSCertificateEvaluation(Document): class LMSCertificateEvaluation(Document):
pass pass
@frappe.whitelist() @frappe.whitelist()
def create_lms_certificate(source_name, target_doc=None): def create_lms_certificate(source_name, target_doc=None):
doc = get_mapped_doc("LMS Certificate Evaluation", source_name, { doc = get_mapped_doc(
"LMS Certificate Evaluation": { "LMS Certificate Evaluation",
"doctype": "LMS Certificate" source_name,
} {"LMS Certificate Evaluation": {"doctype": "LMS Certificate"}},
}, target_doc) target_doc,
)
return doc return doc

View File

@@ -1,23 +1,23 @@
// Copyright (c) 2022, Frappe and contributors // Copyright (c) 2022, Frappe and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Certificate Request', { frappe.ui.form.on("LMS Certificate Request", {
refresh: function (frm) { refresh: function (frm) {
frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => { frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation", method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation",
frm: frm frm: frm,
}); });
}); });
}, },
onload: function (frm) { onload: function (frm) {
frm.set_query('member', function(doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
} },
}); });

View File

@@ -2,54 +2,61 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe import _ from frappe.utils import format_date, format_time, getdate
from frappe.utils import getdate, format_date, format_time
class LMSCertificateRequest(Document): class LMSCertificateRequest(Document):
def validate(self): def validate(self):
self.validate_if_existing_requests() self.validate_if_existing_requests()
def validate_if_existing_requests(self): def validate_if_existing_requests(self):
existing_requests = frappe.get_all("LMS Certificate Request", { existing_requests = frappe.get_all(
"member": self.member, "LMS Certificate Request",
"course": self.course {"member": self.member, "course": self.course},
}, ["date", "start_time", "course"]) ["date", "start_time", "course"],
)
for req in existing_requests: for req in existing_requests:
if req.date == getdate(self.date) and getdate() <= getdate(self.date): if req.date == getdate(self.date) and getdate() <= getdate(self.date):
course_title = frappe.db.get_value("LMS Course", req.course, "title") course_title = frappe.db.get_value("LMS Course", req.course, "title")
frappe.throw(_(f"You already have an evaluation on {format_date(req.date, 'medium')} at {format_time(req.start_time, 'short')} for the course {course_title}.")) frappe.throw(
_(
f"You already have an evaluation on {format_date(req.date, 'medium')} at {format_time(req.start_time, 'short')} for the course {course_title}."
)
)
@frappe.whitelist() @frappe.whitelist()
def create_certificate_request(course, date, day, start_time, end_time): def create_certificate_request(course, date, day, start_time, end_time):
is_member = frappe.db.exists({ is_member = frappe.db.exists(
"doctype": "LMS Batch Membership", {"doctype": "LMS Batch Membership", "course": course, "member": frappe.session.user}
"course": course, )
"member": frappe.session.user
})
if not is_member: if not is_member:
return return
frappe.get_doc({ frappe.get_doc(
{
"doctype": "LMS Certificate Request", "doctype": "LMS Certificate Request",
"course": course, "course": course,
"member": frappe.session.user, "member": frappe.session.user,
"date": date, "date": date,
"day": day, "day": day,
"start_time": start_time, "start_time": start_time,
"end_time": end_time "end_time": end_time,
}).save(ignore_permissions=True) }
).save(ignore_permissions=True)
@frappe.whitelist() @frappe.whitelist()
def create_lms_certificate_evaluation(source_name, target_doc=None): def create_lms_certificate_evaluation(source_name, target_doc=None):
doc = get_mapped_doc("LMS Certificate Request", source_name, { doc = get_mapped_doc(
"LMS Certificate Request": { "LMS Certificate Request",
"doctype": "LMS Certificate Evaluation" source_name,
} {"LMS Certificate Request": {"doctype": "LMS Certificate Evaluation"}},
}, target_doc) target_doc,
)
return doc return doc

View File

@@ -1,33 +1,30 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course', { frappe.ui.form.on("LMS Course", {
onload: function (frm) { onload: function (frm) {
frm.set_query("chapter", "chapters", function () { frm.set_query("chapter", "chapters", function () {
return { return {
filters: { filters: {
"course": frm.doc.name, course: frm.doc.name,
} },
}; };
}); });
frm.set_query("instructor", "instructors", function () { frm.set_query("instructor", "instructors", function () {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
frm.set_query("course", "related_courses", function () { frm.set_query("course", "related_courses", function () {
return { return {
filters: { filters: {
"published": true, published: true,
} },
}; };
}); });
},
}
}); });

View File

@@ -1,56 +1,53 @@
# Copyright (c) 2021, Frappe and contributors # Copyright (c) 2021, Frappe and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals import json
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
import json
from ...utils import generate_slug, validate_image
from frappe.utils import cint from frappe.utils import cint
from lms.lms.utils import get_chapters from lms.lms.utils import get_chapters
from ...utils import generate_slug, validate_image
class LMSCourse(Document): class LMSCourse(Document):
def validate(self): def validate(self):
self.validate_instructors() self.validate_instructors()
self.validate_status() self.validate_status()
self.image = validate_image(self.image) self.image = validate_image(self.image)
def validate_instructors(self): def validate_instructors(self):
if self.is_new() and not self.instructors: if self.is_new() and not self.instructors:
frappe.get_doc({ frappe.get_doc(
{
"doctype": "Course Instructor", "doctype": "Course Instructor",
"instructor": self.owner, "instructor": self.owner,
"parent": self.name, "parent": self.name,
"parentfield": "instructors", "parentfield": "instructors",
"parenttype": "LMS Course" "parenttype": "LMS Course",
}).save(ignore_permissions=True) }
).save(ignore_permissions=True)
def validate_status(self): def validate_status(self):
if self.published: if self.published:
self.status = "Approved" self.status = "Approved"
def on_update(self): def on_update(self):
if not self.upcoming and self.has_value_changed("upcoming"): if not self.upcoming and self.has_value_changed("upcoming"):
self.send_email_to_interested_users() self.send_email_to_interested_users()
def send_email_to_interested_users(self): def send_email_to_interested_users(self):
interested_users = frappe.get_all("LMS Course Interest", { interested_users = frappe.get_all(
"course": self.name "LMS Course Interest", {"course": self.name}, ["name", "user"]
}, )
["name", "user"])
subject = self.title + " is available!" subject = self.title + " is available!"
args = { args = {
"title": self.title, "title": self.title,
"course_link": "/courses/{0}".format(self.name), "course_link": f"/courses/{self.name}",
"app_name": frappe.db.get_single_value("System Settings", "app_name"), "app_name": frappe.db.get_single_value("System Settings", "app_name"),
"site_url": frappe.utils.get_url() "site_url": frappe.utils.get_url(),
} }
for user in interested_users: for user in interested_users:
@@ -61,33 +58,32 @@ class LMSCourse(Document):
header=[subject, "green"], header=[subject, "green"],
template="lms_course_interest", template="lms_course_interest",
args=args, args=args,
now = True) now=True,
frappe.enqueue(method=frappe.sendmail, queue='short', timeout=300, is_async=True, **email_args) )
frappe.enqueue(
method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args
)
frappe.db.set_value("LMS Course Interest", user.name, "email_sent", True) frappe.db.set_value("LMS Course Interest", user.name, "email_sent", True)
def autoname(self): def autoname(self):
if not self.name: if not self.name:
self.name = generate_slug(self.title, "LMS Course") self.name = generate_slug(self.title, "LMS Course")
def __repr__(self): def __repr__(self):
return f"<Course#{self.name}>" return f"<Course#{self.name}>"
def has_mentor(self, email): def has_mentor(self, email):
"""Checks if this course has a mentor with given email. """Checks if this course has a mentor with given email."""
"""
if not email or email == "Guest": if not email or email == "Guest":
return False return False
mapping = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name, "mentor": email}) mapping = frappe.get_all(
"LMS Course Mentor Mapping", {"course": self.name, "mentor": email}
)
return mapping != [] return mapping != []
def add_mentor(self, email): def add_mentor(self, email):
"""Adds a new mentor to the course. """Adds a new mentor to the course."""
"""
if not email: if not email:
raise ValueError("Invalid email") raise ValueError("Invalid email")
if email == "Guest": if email == "Guest":
@@ -97,14 +93,11 @@ class LMSCourse(Document):
if self.has_mentor(email): if self.has_mentor(email):
return return
doc = frappe.get_doc({ doc = frappe.get_doc(
"doctype": "LMS Course Mentor Mapping", {"doctype": "LMS Course Mentor Mapping", "course": self.name, "mentor": email}
"course": self.name, )
"mentor": email
})
doc.insert() doc.insert()
def get_student_batch(self, email): def get_student_batch(self, email):
"""Returns the batch the given student is part of. """Returns the batch the given student is part of.
@@ -115,44 +108,37 @@ class LMSCourse(Document):
batch_name = frappe.get_value( batch_name = frappe.get_value(
doctype="LMS Batch Membership", doctype="LMS Batch Membership",
filters={ filters={"course": self.name, "member_type": "Student", "member": email},
"course": self.name, fieldname="batch",
"member_type": "Student", )
"member": email
},
fieldname="batch")
return batch_name and frappe.get_doc("LMS Batch", batch_name) return batch_name and frappe.get_doc("LMS Batch", batch_name)
def get_batches(self, mentor=None): def get_batches(self, mentor=None):
batches = frappe.get_all("LMS Batch", {"course": self.name}) batches = frappe.get_all("LMS Batch", {"course": self.name})
if mentor: if mentor:
# TODO: optimize this # TODO: optimize this
memberships = frappe.db.get_all( memberships = frappe.db.get_all(
"LMS Batch Membership", "LMS Batch Membership", {"member": mentor}, ["batch"]
{"member": mentor}, )
["batch"])
batch_names = {m.batch for m in memberships} batch_names = {m.batch for m in memberships}
return [b for b in batches if b.name in batch_names] return [b for b in batches if b.name in batch_names]
def get_cohorts(self): def get_cohorts(self):
return frappe.get_all("Cohort", return frappe.get_all(
"Cohort",
{"course": self.name}, {"course": self.name},
["name", "slug", "title", "begin_date", "end_date"], ["name", "slug", "title", "begin_date", "end_date"],
order_by="creation") order_by="creation",
)
def get_cohort(self, cohort_slug): def get_cohort(self, cohort_slug):
name = frappe.get_value("Cohort", {"course": self.name, "slug": cohort_slug}) name = frappe.get_value("Cohort", {"course": self.name, "slug": cohort_slug})
return name and frappe.get_doc("Cohort", name) return name and frappe.get_doc("Cohort", name)
def reindex_exercises(self): def reindex_exercises(self):
for i, c in enumerate(get_chapters(self.name), start=1): for i, c in enumerate(get_chapters(self.name), start=1):
self._reindex_exercises_in_chapter(c, i) self._reindex_exercises_in_chapter(c, i)
def _reindex_exercises_in_chapter(self, c, index): def _reindex_exercises_in_chapter(self, c, index):
i = 1 i = 1
for lesson in self.get_lessons(c): for lesson in self.get_lessons(c):
@@ -162,9 +148,10 @@ class LMSCourse(Document):
exercise.save() exercise.save()
i += 1 i += 1
def get_all_memberships(self, member): def get_all_memberships(self, member):
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": self.name}, ["batch"]) all_memberships = frappe.get_all(
"LMS Batch Membership", {"member": member, "course": self.name}, ["batch"]
)
for membership in all_memberships: for membership in all_memberships:
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title") membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
return all_memberships return all_memberships
@@ -173,7 +160,7 @@ class LMSCourse(Document):
@frappe.whitelist() @frappe.whitelist()
def reindex_exercises(doc): def reindex_exercises(doc):
course_data = json.loads(doc) course_data = json.loads(doc)
course = frappe.get_doc("LMS Course", course_data['name']) course = frappe.get_doc("LMS Course", course_data["name"])
course.reindex_exercises() course.reindex_exercises()
frappe.msgprint("All exercises in this course have been re-indexed.") frappe.msgprint("All exercises in this course have been re-indexed.")
@@ -181,16 +168,16 @@ def reindex_exercises(doc):
@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
def search_course(text): def search_course(text):
search_courses = [] search_courses = []
courses = frappe.get_all("LMS Course", courses = frappe.get_all(
filters= { "LMS Course",
"published": True filters={"published": True},
},
or_filters={ or_filters={
"title": ["like", "%{0}%".format(text)], "title": ["like", f"%{text}%"],
"tags": ["like", "%{0}%".format(text)], "tags": ["like", f"%{text}%"],
"short_introduction": ["like", "%{0}%".format(text)], "short_introduction": ["like", f"%{text}%"],
"description": ["like", "%{0}%".format(text)], "description": ["like", f"%{text}%"],
}) },
)
""" for course in courses: """ for course in courses:
search_courses.append(frappe.get_doc("LMS Course", course)) """ search_courses.append(frappe.get_doc("LMS Course", course)) """
@@ -214,15 +201,24 @@ def submit_for_review(course):
@frappe.whitelist() @frappe.whitelist()
def save_course(tags, title, short_introduction, video_link, description, course, published, upcoming, image=None): def save_course(
tags,
title,
short_introduction,
video_link,
description,
course,
published,
upcoming,
image=None,
):
if course: if course:
doc = frappe.get_doc("LMS Course", course) doc = frappe.get_doc("LMS Course", course)
else: else:
doc = frappe.get_doc({ doc = frappe.get_doc({"doctype": "LMS Course"})
"doctype": "LMS Course"
})
doc.update({ doc.update(
{
"title": title, "title": title,
"short_introduction": short_introduction, "short_introduction": short_introduction,
"video_link": video_link, "video_link": video_link,
@@ -230,8 +226,9 @@ def save_course(tags, title, short_introduction, video_link, description, course
"description": description, "description": description,
"tags": tags, "tags": tags,
"published": cint(published), "published": cint(published),
"upcoming": cint(upcoming) "upcoming": cint(upcoming),
}) }
)
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
return doc.name return doc.name
@@ -241,27 +238,23 @@ def save_chapter(course, title, chapter_description, idx, chapter):
if chapter: if chapter:
doc = frappe.get_doc("Course Chapter", chapter) doc = frappe.get_doc("Course Chapter", chapter)
else: else:
doc = frappe.get_doc({ doc = frappe.get_doc({"doctype": "Course Chapter"})
"doctype": "Course Chapter"
})
doc.update({ doc.update({"course": course, "title": title, "description": chapter_description})
"course": course,
"title": title,
"description": chapter_description
})
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
if chapter: if chapter:
chapter_reference = frappe.get_doc("Chapter Reference", {"chapter": chapter}) chapter_reference = frappe.get_doc("Chapter Reference", {"chapter": chapter})
else: else:
chapter_reference = frappe.get_doc({ chapter_reference = frappe.get_doc(
{
"doctype": "Chapter Reference", "doctype": "Chapter Reference",
"parent": course, "parent": course,
"parenttype": "LMS Course", "parenttype": "LMS Course",
"parentfield": "chapters", "parentfield": "chapters",
"idx": idx "idx": idx,
}) }
)
chapter_reference.update({"chapter": doc.name}) chapter_reference.update({"chapter": doc.name})
chapter_reference.save(ignore_permissions=True) chapter_reference.save(ignore_permissions=True)
@@ -270,15 +263,25 @@ def save_chapter(course, title, chapter_description, idx, chapter):
@frappe.whitelist() @frappe.whitelist()
def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None, question=None, file_type=None): def save_lesson(
title,
body,
chapter,
preview,
idx,
lesson,
youtube=None,
quiz_id=None,
question=None,
file_type=None,
):
if lesson: if lesson:
doc = frappe.get_doc("Course Lesson", lesson) doc = frappe.get_doc("Course Lesson", lesson)
else: else:
doc = frappe.get_doc({ doc = frappe.get_doc({"doctype": "Course Lesson"})
"doctype": "Course Lesson"
})
doc.update({ doc.update(
{
"chapter": chapter, "chapter": chapter,
"title": title, "title": title,
"body": body, "body": body,
@@ -286,20 +289,23 @@ def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_i
"youtube": youtube, "youtube": youtube,
"quiz_id": quiz_id, "quiz_id": quiz_id,
"question": question, "question": question,
"file_type": file_type "file_type": file_type,
}) }
)
doc.save(ignore_permissions=True) doc.save(ignore_permissions=True)
if lesson: if lesson:
lesson_reference = frappe.get_doc("Lesson Reference", {"lesson": lesson}) lesson_reference = frappe.get_doc("Lesson Reference", {"lesson": lesson})
else: else:
lesson_reference = frappe.get_doc({ lesson_reference = frappe.get_doc(
{
"doctype": "Lesson Reference", "doctype": "Lesson Reference",
"parent": chapter, "parent": chapter,
"parenttype": "Course Chapter", "parenttype": "Course Chapter",
"parentfield": "lessons", "parentfield": "lessons",
"idx": idx "idx": idx,
}) }
)
lesson_reference.update({"lesson": doc.name}) lesson_reference.update({"lesson": doc.name})
lesson_reference.save(ignore_permissions=True) lesson_reference.save(ignore_permissions=True)

View File

@@ -1,22 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
import unittest
import frappe import frappe
from .lms_course import LMSCourse from .lms_course import LMSCourse
import unittest
class TestLMSCourse(unittest.TestCase): class TestLMSCourse(unittest.TestCase):
def test_new_course(self): def test_new_course(self):
course = new_course("Test Course") course = new_course("Test Course")
assert course.title == "Test Course" assert course.title == "Test Course"
assert course.name == "test-course" assert course.name == "test-course"
# disabled this test as it is failing # disabled this test as it is failing
def _test_add_mentors(self): def _test_add_mentors(self):
course = new_course("Test Course") course = new_course("Test Course")
@@ -26,10 +23,11 @@ class TestLMSCourse(unittest.TestCase):
course.add_mentor("tester@example.com") course.add_mentor("tester@example.com")
mentors = course.get_mentors() mentors = course.get_mentors()
mentors_data = [dict(email=mentor.email, batch_count=mentor.batch_count) for mentor in mentors] mentors_data = [
dict(email=mentor.email, batch_count=mentor.batch_count) for mentor in mentors
]
assert mentors_data == [{"email": "tester@example.com", "batch_count": 0}] assert mentors_data == [{"email": "tester@example.com", "batch_count": 0}]
def tearDown(self): def tearDown(self):
if frappe.db.exists("User", "tester@example.com"): if frappe.db.exists("User", "tester@example.com"):
frappe.delete_doc("User", "tester@example.com") frappe.delete_doc("User", "tester@example.com")
@@ -42,7 +40,7 @@ class TestLMSCourse(unittest.TestCase):
frappe.db.delete("LMS Batch", {"course": "test-course"}) frappe.db.delete("LMS Batch", {"course": "test-course"})
frappe.db.delete("LMS Course Mentor Mapping", {"course": "test-course"}) frappe.db.delete("LMS Course Mentor Mapping", {"course": "test-course"})
frappe.db.delete("Course Instructor", {"parent": "test-course"}) frappe.db.delete("Course Instructor", {"parent": "test-course"})
frappe.db.sql('delete from `tabCourse Instructor`') frappe.db.sql("delete from `tabCourse Instructor`")
frappe.delete_doc("LMS Course", "test-course") frappe.delete_doc("LMS Course", "test-course")
@@ -55,7 +53,7 @@ def new_user(name, email):
"doctype": "User", "doctype": "User",
"email": email, "email": email,
"first_name": name, "first_name": name,
"send_welcome_email": False "send_welcome_email": False,
} }
doc = frappe.get_doc(filters) doc = frappe.get_doc(filters)
@@ -73,7 +71,7 @@ def new_course(title, additional_filters=None):
"doctype": "LMS Course", "doctype": "LMS Course",
"title": title, "title": title,
"short_introduction": title, "short_introduction": title,
"description": title "description": title,
} }
if additional_filters: if additional_filters:
@@ -87,7 +85,6 @@ def new_course(title, additional_filters=None):
def create_evaluator(): def create_evaluator():
if not frappe.db.exists("Course Evaluator", "evaluator@example.com"): if not frappe.db.exists("Course Evaluator", "evaluator@example.com"):
new_user("Evaluator", "evaluator@example.com") new_user("Evaluator", "evaluator@example.com")
frappe.get_doc({ frappe.get_doc(
"doctype": "Course Evaluator", {"doctype": "Course Evaluator", "evaluator": "evaluator@example.com"}
"evaluator": "evaluator@example.com" ).save(ignore_permissions=True)
}).save(ignore_permissions=True)

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course Enrollment', { frappe.ui.form.on("LMS Course Enrollment", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class LMSCourseEnrollment(Document): class LMSCourseEnrollment(Document):
pass pass

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
# import frappe # import frappe
import unittest import unittest
class TestLMSCourseEnrollment(unittest.TestCase): class TestLMSCourseEnrollment(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course Interest', { frappe.ui.form.on("LMS Course Interest", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,15 +4,17 @@
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
class LMSCourseInterest(Document): class LMSCourseInterest(Document):
pass pass
@frappe.whitelist() @frappe.whitelist()
def capture_interest(course): def capture_interest(course):
data = { data = {
"doctype": "LMS Course Interest", "doctype": "LMS Course Interest",
"course": course, "course": course,
"user": frappe.session.user "user": frappe.session.user,
} }
if not frappe.db.exists(data): if not frappe.db.exists(data):
frappe.get_doc(data).save(ignore_permissions=True) frappe.get_doc(data).save(ignore_permissions=True)

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestLMSCourseInterest(unittest.TestCase): class TestLMSCourseInterest(unittest.TestCase):
pass pass

View File

@@ -1,13 +1,13 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course Mentor Mapping', { frappe.ui.form.on("LMS Course Mentor Mapping", {
onload: function (frm) { onload: function (frm) {
frm.set_query('mentor', function(doc) { frm.set_query("mentor", function (doc) {
return { return {
filters: { filters: {
"ignore_user_type": 1, ignore_user_type: 1,
} },
}; };
}); });
}, },

View File

@@ -1,18 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors # Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.model.document import Document
class LMSCourseMentorMapping(Document): class LMSCourseMentorMapping(Document):
def validate(self): def validate(self):
duplicate_mapping = frappe.get_all("LMS Course Mentor Mapping", duplicate_mapping = frappe.get_all(
filters = { "LMS Course Mentor Mapping", filters={"course": self.course, "mentor": self.mentor}
"course": self.course, )
"mentor": self.mentor
})
if len(duplicate_mapping): if len(duplicate_mapping):
frappe.throw(_("{0} is already a mentor for course {1}").format(self.mentor_name, self.course)) frappe.throw(
_("{0} is already a mentor for course {1}").format(self.mentor_name, self.course)
)

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors # Copyright (c) 2021, FOSS United and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
# import frappe # import frappe
import unittest import unittest
class TestLMSCourseMentorMapping(unittest.TestCase): class TestLMSCourseMentorMapping(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course Progress', { frappe.ui.form.on("LMS Course Progress", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class LMSCourseProgress(Document): class LMSCourseProgress(Document):
pass pass

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestLMSCourseProgress(unittest.TestCase): class TestLMSCourseProgress(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course Review', { frappe.ui.form.on("LMS Course Review", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -5,23 +5,19 @@ import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import cint from frappe.utils import cint
class LMSCourseReview(Document): class LMSCourseReview(Document):
pass pass
@frappe.whitelist() @frappe.whitelist()
def submit_review(rating, review, course): def submit_review(rating, review, course):
out_of_ratings = frappe.db.get_all("DocField", out_of_ratings = frappe.db.get_all(
{ "DocField", {"parent": "LMS Course Review", "fieldtype": "Rating"}, ["options"]
"parent": "LMS Course Review", )
"fieldtype": "Rating"
},
["options"])
out_of_ratings = (len(out_of_ratings) and out_of_ratings[0].options) or 5 out_of_ratings = (len(out_of_ratings) and out_of_ratings[0].options) or 5
rating = cint(rating) / out_of_ratings rating = cint(rating) / out_of_ratings
frappe.get_doc({ frappe.get_doc(
"doctype": "LMS Course Review", {"doctype": "LMS Course Review", "rating": rating, "review": review, "course": course}
"rating": rating, ).save(ignore_permissions=True)
"review": review,
"course": course
}).save(ignore_permissions=True)
return "OK" return "OK"

View File

@@ -4,5 +4,6 @@
# import frappe # import frappe
import unittest import unittest
class TestLMSCourseReview(unittest.TestCase): class TestLMSCourseReview(unittest.TestCase):
pass pass

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2021, FOSS United and contributors // Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Mentor Request', { frappe.ui.form.on("LMS Mentor Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

Some files were not shown because too many files have changed in this diff Show More