Merge pull request #422 from pateljannat/semgrep
This commit is contained in:
@@ -9,7 +9,7 @@ root = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_style = tab
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Python
|
||||
|
||||
37
.flake8
Normal file
37
.flake8
Normal file
@@ -0,0 +1,37 @@
|
||||
[flake8]
|
||||
ignore =
|
||||
E121,
|
||||
E126,
|
||||
E127,
|
||||
E128,
|
||||
E203,
|
||||
E225,
|
||||
E226,
|
||||
E231,
|
||||
E241,
|
||||
E251,
|
||||
E261,
|
||||
E265,
|
||||
E302,
|
||||
E303,
|
||||
E305,
|
||||
E402,
|
||||
E501,
|
||||
E741,
|
||||
W291,
|
||||
W292,
|
||||
W293,
|
||||
W391,
|
||||
W503,
|
||||
W504,
|
||||
F403,
|
||||
B007,
|
||||
B950,
|
||||
W191,
|
||||
E124, # closing bracket, irritating while writing QB code
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E101, # ensured by use of black
|
||||
|
||||
max-line-length = 200
|
||||
exclude=.github/helper/semgrep_rules
|
||||
74
.github/helper/flake8.conf
vendored
Normal file
74
.github/helper/flake8.conf
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
[flake8]
|
||||
ignore =
|
||||
B001,
|
||||
B007,
|
||||
B009,
|
||||
B010,
|
||||
B950,
|
||||
E101,
|
||||
E111,
|
||||
E114,
|
||||
E116,
|
||||
E117,
|
||||
E121,
|
||||
E122,
|
||||
E123,
|
||||
E124,
|
||||
E125,
|
||||
E126,
|
||||
E127,
|
||||
E128,
|
||||
E131,
|
||||
E201,
|
||||
E202,
|
||||
E203,
|
||||
E211,
|
||||
E221,
|
||||
E222,
|
||||
E223,
|
||||
E224,
|
||||
E225,
|
||||
E226,
|
||||
E228,
|
||||
E231,
|
||||
E241,
|
||||
E242,
|
||||
E251,
|
||||
E261,
|
||||
E262,
|
||||
E265,
|
||||
E266,
|
||||
E271,
|
||||
E272,
|
||||
E273,
|
||||
E274,
|
||||
E301,
|
||||
E302,
|
||||
E303,
|
||||
E305,
|
||||
E306,
|
||||
E402,
|
||||
E501,
|
||||
E502,
|
||||
E701,
|
||||
E702,
|
||||
E703,
|
||||
E741,
|
||||
F401,
|
||||
F403,
|
||||
F405,
|
||||
W191,
|
||||
W291,
|
||||
W292,
|
||||
W293,
|
||||
W391,
|
||||
W503,
|
||||
W504,
|
||||
E711,
|
||||
E129,
|
||||
F841,
|
||||
E713,
|
||||
E712,
|
||||
|
||||
|
||||
max-line-length = 200
|
||||
33
.github/workflows/linters.yml
vendored
Normal file
33
.github/workflows/linters.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Linters
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
linters:
|
||||
name: Semantic Commits
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
- name: Download semgrep
|
||||
run: pip install semgrep
|
||||
|
||||
- name: Run Semgrep rules
|
||||
run: semgrep ci --config ./frappe-semgrep-rules/rules
|
||||
59
.pre-commit-config.yaml
Normal file
59
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
exclude: 'node_modules|.git'
|
||||
default_stages: [commit]
|
||||
fail_fast: false
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
files: "frappe.*"
|
||||
exclude: ".*json$|.*txt$|.*csv|.*md|.*svg"
|
||||
- id: check-yaml
|
||||
- id: no-commit-to-branch
|
||||
args: ['--branch', 'main']
|
||||
- id: check-merge-conflict
|
||||
- id: check-ast
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: debug-statements
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.34.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ['--py310-plus']
|
||||
|
||||
- repo: https://github.com/adityahase/black
|
||||
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
|
||||
hooks:
|
||||
- id: black
|
||||
additional_dependencies: ['click==8.0.4']
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v2.7.1
|
||||
hooks:
|
||||
- id: prettier
|
||||
types_or: [javascript]
|
||||
# Ignore any files that might contain jinja / bundles
|
||||
exclude: |
|
||||
(?x)^(
|
||||
lms/public/dist/.*|
|
||||
.*node_modules.*|
|
||||
.*boilerplate.*|
|
||||
lms/www/website_script.js|
|
||||
lms/templates/includes/.*|
|
||||
lms/public/js/lib/.*
|
||||
)$
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: ['flake8-bugbear',]
|
||||
args: ['--config', '.github/helper/flake8.conf']
|
||||
|
||||
ci:
|
||||
autoupdate_schedule: weekly
|
||||
skip: []
|
||||
submodules: false
|
||||
@@ -1,4 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__version__ = '0.0.1'
|
||||
__version__ = "0.0.1"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
|
||||
def get_data():
|
||||
return [
|
||||
{
|
||||
@@ -9,6 +8,6 @@ def get_data():
|
||||
"color": "grey",
|
||||
"icon": "octicon octicon-file-directory",
|
||||
"type": "module",
|
||||
"label": _("Community")
|
||||
"label": _("Community"),
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,5 +7,6 @@ Configuration for docs
|
||||
# headline = "App that does everything"
|
||||
# sub_heading = "Yes, you got that right the first time, everything"
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.brand_html = "Community"
|
||||
|
||||
215
lms/hooks.py
215
lms/hooks.py
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
from . import __version__ as app_version
|
||||
|
||||
app_name = "frappe_lms"
|
||||
@@ -47,7 +45,7 @@ web_include_js = ["website.bundle.js"]
|
||||
|
||||
# website user home page (by Role)
|
||||
# role_home_page = {
|
||||
# "Role": "home_page"
|
||||
# "Role": "home_page"
|
||||
# }
|
||||
|
||||
# Generators
|
||||
@@ -87,8 +85,8 @@ after_uninstall = "lms.install.after_uninstall"
|
||||
# Override standard doctype classes
|
||||
|
||||
override_doctype_class = {
|
||||
"User": "lms.overrides.user.CustomUser",
|
||||
"Web Template": "lms.overrides.web_template.CustomWebTemplate"
|
||||
"User": "lms.overrides.user.CustomUser",
|
||||
"Web Template": "lms.overrides.web_template.CustomWebTemplate",
|
||||
}
|
||||
|
||||
# Document Events
|
||||
@@ -96,18 +94,16 @@ override_doctype_class = {
|
||||
# Hook on document methods and events
|
||||
|
||||
doc_events = {
|
||||
"Discussion Reply": {
|
||||
"after_insert": "lms.lms.utils.create_notification_log"
|
||||
}
|
||||
"Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"}
|
||||
}
|
||||
|
||||
# Scheduled Tasks
|
||||
# ---------------
|
||||
#scheduler_events = {
|
||||
# "daily": [
|
||||
# "erpnext.stock.reorder_item.reorder_item"
|
||||
# ]
|
||||
#}
|
||||
# scheduler_events = {
|
||||
# "daily": [
|
||||
# "erpnext.stock.reorder_item.reorder_item"
|
||||
# ]
|
||||
# }
|
||||
|
||||
fixtures = ["Custom Field", "Function", "Industry"]
|
||||
|
||||
@@ -136,79 +132,94 @@ fixtures = ["Custom Field", "Function", "Industry"]
|
||||
|
||||
# Add all simple route rules here
|
||||
website_route_rules = [
|
||||
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
||||
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
||||
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
|
||||
{"from_route": "/courses/<course>/learn", "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/<quizname>", "to_route": "batch/quiz"},
|
||||
{"from_route": "/courses/<course>/progress", "to_route": "batch/progress"},
|
||||
{"from_route": "/courses/<course>/join", "to_route": "batch/join"},
|
||||
{"from_route": "/courses/<course>/manage", "to_route": "cohorts"},
|
||||
{"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>/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": "/jobs/<job>", "to_route": "jobs/job"}
|
||||
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
||||
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
||||
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
|
||||
{"from_route": "/courses/<course>/learn", "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/<quizname>", "to_route": "batch/quiz"},
|
||||
{"from_route": "/courses/<course>/progress", "to_route": "batch/progress"},
|
||||
{"from_route": "/courses/<course>/join", "to_route": "batch/join"},
|
||||
{"from_route": "/courses/<course>/manage", "to_route": "cohorts"},
|
||||
{"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>/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": "/jobs/<job>", "to_route": "jobs/job"},
|
||||
]
|
||||
|
||||
website_redirects = [
|
||||
{"source": "/update-profile", "target": "/edit-profile"},
|
||||
{"source": "/dashboard", "target": "/courses"},
|
||||
{"source": "/update-profile", "target": "/edit-profile"},
|
||||
{"source": "/dashboard", "target": "/courses"},
|
||||
]
|
||||
|
||||
update_website_context = [
|
||||
'lms.widgets.update_website_context',
|
||||
"lms.widgets.update_website_context",
|
||||
]
|
||||
|
||||
jinja = {
|
||||
"methods": [
|
||||
"lms.page_renderers.get_profile_url",
|
||||
"lms.overrides.user.get_enrolled_courses",
|
||||
"lms.overrides.user.get_course_membership",
|
||||
"lms.overrides.user.get_authored_courses",
|
||||
"lms.overrides.user.get_palette",
|
||||
"lms.lms.utils.get_membership",
|
||||
"lms.lms.utils.get_lessons",
|
||||
"lms.lms.utils.get_tags",
|
||||
"lms.lms.utils.get_instructors",
|
||||
"lms.lms.utils.get_students",
|
||||
"lms.lms.utils.get_average_rating",
|
||||
"lms.lms.utils.is_certified",
|
||||
"lms.lms.utils.get_lesson_index",
|
||||
"lms.lms.utils.get_lesson_url",
|
||||
"lms.lms.utils.get_chapters",
|
||||
"lms.lms.utils.get_slugified_chapter_title",
|
||||
"lms.lms.utils.get_progress",
|
||||
"lms.lms.utils.render_html",
|
||||
"lms.lms.utils.is_mentor",
|
||||
"lms.lms.utils.is_cohort_staff",
|
||||
"lms.lms.utils.get_mentors",
|
||||
"lms.lms.utils.get_reviews",
|
||||
"lms.lms.utils.is_eligible_to_review",
|
||||
"lms.lms.utils.get_initial_members",
|
||||
"lms.lms.utils.get_sorted_reviews",
|
||||
"lms.lms.utils.is_instructor",
|
||||
"lms.lms.utils.convert_number_to_character",
|
||||
"lms.lms.utils.get_signup_optin_checks",
|
||||
"lms.lms.utils.get_popular_courses",
|
||||
"lms.lms.utils.format_amount",
|
||||
"lms.lms.utils.first_lesson_exists",
|
||||
"lms.lms.utils.get_courses_under_review",
|
||||
"lms.lms.utils.has_course_instructor_role",
|
||||
"lms.lms.utils.has_course_moderator_role",
|
||||
"lms.lms.utils.get_certificates",
|
||||
"lms.lms.utils.format_number",
|
||||
"lms.lms.utils.get_lesson_count",
|
||||
"lms.lms.utils.get_all_memberships",
|
||||
"lms.lms.utils.get_filtered_membership",
|
||||
"lms.lms.utils.show_start_learing_cta",
|
||||
"lms.lms.utils.can_create_courses"
|
||||
],
|
||||
"filters": []
|
||||
"methods": [
|
||||
"lms.page_renderers.get_profile_url",
|
||||
"lms.overrides.user.get_enrolled_courses",
|
||||
"lms.overrides.user.get_course_membership",
|
||||
"lms.overrides.user.get_authored_courses",
|
||||
"lms.overrides.user.get_palette",
|
||||
"lms.lms.utils.get_membership",
|
||||
"lms.lms.utils.get_lessons",
|
||||
"lms.lms.utils.get_tags",
|
||||
"lms.lms.utils.get_instructors",
|
||||
"lms.lms.utils.get_students",
|
||||
"lms.lms.utils.get_average_rating",
|
||||
"lms.lms.utils.is_certified",
|
||||
"lms.lms.utils.get_lesson_index",
|
||||
"lms.lms.utils.get_lesson_url",
|
||||
"lms.lms.utils.get_chapters",
|
||||
"lms.lms.utils.get_slugified_chapter_title",
|
||||
"lms.lms.utils.get_progress",
|
||||
"lms.lms.utils.render_html",
|
||||
"lms.lms.utils.is_mentor",
|
||||
"lms.lms.utils.is_cohort_staff",
|
||||
"lms.lms.utils.get_mentors",
|
||||
"lms.lms.utils.get_reviews",
|
||||
"lms.lms.utils.is_eligible_to_review",
|
||||
"lms.lms.utils.get_initial_members",
|
||||
"lms.lms.utils.get_sorted_reviews",
|
||||
"lms.lms.utils.is_instructor",
|
||||
"lms.lms.utils.convert_number_to_character",
|
||||
"lms.lms.utils.get_signup_optin_checks",
|
||||
"lms.lms.utils.get_popular_courses",
|
||||
"lms.lms.utils.format_amount",
|
||||
"lms.lms.utils.first_lesson_exists",
|
||||
"lms.lms.utils.get_courses_under_review",
|
||||
"lms.lms.utils.has_course_instructor_role",
|
||||
"lms.lms.utils.has_course_moderator_role",
|
||||
"lms.lms.utils.get_certificates",
|
||||
"lms.lms.utils.format_number",
|
||||
"lms.lms.utils.get_lesson_count",
|
||||
"lms.lms.utils.get_all_memberships",
|
||||
"lms.lms.utils.get_filtered_membership",
|
||||
"lms.lms.utils.show_start_learing_cta",
|
||||
"lms.lms.utils.can_create_courses",
|
||||
],
|
||||
"filters": [],
|
||||
}
|
||||
## Specify the additional tabs to be included in the user profile page.
|
||||
## Each entry must be a subclass of lms.lms.plugins.ProfileTab
|
||||
@@ -219,42 +230,42 @@ jinja = {
|
||||
## subclass of lms.plugins.PageExtension
|
||||
# lms_lesson_page_extension = None
|
||||
|
||||
#lms_lesson_page_extensions = [
|
||||
# "lms.plugins.LiveCodeExtension"
|
||||
#]
|
||||
# lms_lesson_page_extensions = [
|
||||
# "lms.plugins.LiveCodeExtension"
|
||||
# ]
|
||||
|
||||
profile_mandatory_fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"user_image",
|
||||
"bio",
|
||||
"linkedin",
|
||||
"education",
|
||||
"skill",
|
||||
"preferred_functions",
|
||||
"preferred_industries",
|
||||
"dream_companies",
|
||||
"attire",
|
||||
"collaboration",
|
||||
"role",
|
||||
"location_preference",
|
||||
"time",
|
||||
"company_type"
|
||||
"first_name",
|
||||
"last_name",
|
||||
"user_image",
|
||||
"bio",
|
||||
"linkedin",
|
||||
"education",
|
||||
"skill",
|
||||
"preferred_functions",
|
||||
"preferred_industries",
|
||||
"dream_companies",
|
||||
"attire",
|
||||
"collaboration",
|
||||
"role",
|
||||
"location_preference",
|
||||
"time",
|
||||
"company_type",
|
||||
]
|
||||
|
||||
## Markdown Macros for Lessons
|
||||
lms_markdown_macro_renderers = {
|
||||
"Exercise": "lms.plugins.exercise_renderer",
|
||||
"Quiz": "lms.plugins.quiz_renderer",
|
||||
"YouTubeVideo": "lms.plugins.youtube_video_renderer",
|
||||
"Video": "lms.plugins.video_renderer",
|
||||
"Assignment": "lms.plugins.assignment_renderer"
|
||||
"Exercise": "lms.plugins.exercise_renderer",
|
||||
"Quiz": "lms.plugins.quiz_renderer",
|
||||
"YouTubeVideo": "lms.plugins.youtube_video_renderer",
|
||||
"Video": "lms.plugins.video_renderer",
|
||||
"Assignment": "lms.plugins.assignment_renderer",
|
||||
}
|
||||
|
||||
# page_renderer to manage profile pages
|
||||
page_renderer = [
|
||||
"lms.page_renderers.ProfileRedirectPage",
|
||||
"lms.page_renderers.ProfilePage"
|
||||
"lms.page_renderers.ProfilePage",
|
||||
]
|
||||
|
||||
# set this to "/" to have profiles on the top-level
|
||||
|
||||
105
lms/install.py
105
lms/install.py
@@ -3,58 +3,91 @@ from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
|
||||
|
||||
|
||||
def after_sync():
|
||||
create_lms_roles()
|
||||
set_default_home()
|
||||
add_all_roles_to("Administrator")
|
||||
create_lms_roles()
|
||||
set_default_home()
|
||||
add_all_roles_to("Administrator")
|
||||
|
||||
|
||||
def after_uninstall():
|
||||
delete_custom_fields()
|
||||
delete_custom_fields()
|
||||
|
||||
|
||||
def create_lms_roles():
|
||||
create_instructor_role()
|
||||
create_moderator_role()
|
||||
create_instructor_role()
|
||||
create_moderator_role()
|
||||
|
||||
|
||||
def set_default_home():
|
||||
frappe.db.set_value("Portal Settings", None, "default_portal_home", "/courses")
|
||||
frappe.db.set_value("Portal Settings", None, "default_portal_home", "/courses")
|
||||
|
||||
|
||||
def create_instructor_role():
|
||||
if not frappe.db.exists("Role", "Course Instructor"):
|
||||
role = frappe.get_doc({
|
||||
"doctype": "Role",
|
||||
"role_name": "Course Instructor",
|
||||
"home_page": "",
|
||||
"desk_access": 0
|
||||
})
|
||||
role.save(ignore_permissions=True)
|
||||
if not frappe.db.exists("Role", "Course Instructor"):
|
||||
role = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Role",
|
||||
"role_name": "Course Instructor",
|
||||
"home_page": "",
|
||||
"desk_access": 0,
|
||||
}
|
||||
)
|
||||
role.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def create_moderator_role():
|
||||
if not frappe.db.exists("Role", "Course Moderator"):
|
||||
role = frappe.get_doc({
|
||||
"doctype": "Role",
|
||||
"role_name": "Course Moderator",
|
||||
"home_page": "",
|
||||
"desk_access": 0
|
||||
})
|
||||
role.save(ignore_permissions=True)
|
||||
if not frappe.db.exists("Role", "Course Moderator"):
|
||||
role = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Role",
|
||||
"role_name": "Course Moderator",
|
||||
"home_page": "",
|
||||
"desk_access": 0,
|
||||
}
|
||||
)
|
||||
role.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def delete_custom_fields():
|
||||
fields = [ "user_category", "headline", "college", "city", "verify_terms", "country",
|
||||
"preferred_location", "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"
|
||||
]
|
||||
fields = [
|
||||
"user_category",
|
||||
"headline",
|
||||
"college",
|
||||
"city",
|
||||
"verify_terms",
|
||||
"country",
|
||||
"preferred_location",
|
||||
"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:
|
||||
frappe.db.delete("Custom Field", {"fieldname": field})
|
||||
frappe.db.commit()
|
||||
for field in fields:
|
||||
frappe.db.delete("Custom Field", {"fieldname": field})
|
||||
frappe.db.commit()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Job Opportunity', {
|
||||
frappe.ui.form.on("Job Opportunity", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -2,40 +2,40 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.user import get_system_managers
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import get_link_to_form
|
||||
from frappe.utils.user import get_system_managers
|
||||
|
||||
from lms.lms.utils import validate_image
|
||||
|
||||
|
||||
class JobOpportunity(Document):
|
||||
def validate(self):
|
||||
self.validate_urls()
|
||||
self.company_logo = validate_image(self.company_logo)
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.validate_urls()
|
||||
self.company_logo = validate_image(self.company_logo)
|
||||
|
||||
|
||||
def validate_urls(self):
|
||||
frappe.utils.validate_url(self.company_website, True)
|
||||
frappe.utils.validate_url(self.application_link, True)
|
||||
def validate_urls(self):
|
||||
frappe.utils.validate_url(self.company_website, True)
|
||||
frappe.utils.validate_url(self.application_link, True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def report(job, reason):
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
user = frappe.db.get_value("User", frappe.session.user, "full_name")
|
||||
subject = _("User {0} has reported the job post {1}").format(user, job)
|
||||
args = {
|
||||
"job": job,
|
||||
"job_url": get_link_to_form("Job Opportunity", job),
|
||||
"user": user,
|
||||
"reason": reason
|
||||
}
|
||||
frappe.sendmail(
|
||||
recipients = system_managers,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template = "job_report",
|
||||
args=args,
|
||||
now=True)
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
user = frappe.db.get_value("User", frappe.session.user, "full_name")
|
||||
subject = _("User {0} has reported the job post {1}").format(user, job)
|
||||
args = {
|
||||
"job": job,
|
||||
"job_url": get_link_to_form("Job Opportunity", job),
|
||||
"user": user,
|
||||
"reason": reason,
|
||||
}
|
||||
frappe.sendmail(
|
||||
recipients=system_managers,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template="job_report",
|
||||
args=args,
|
||||
now=True,
|
||||
)
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestJobOpportunity(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2022, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Job Settings', {
|
||||
frappe.ui.form.on("Job Settings", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class JobSettings(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestJobSettings(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def get_context(context):
|
||||
# do your magic here
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
frappe.ready(function() {
|
||||
frappe.ready(function () {
|
||||
frappe.web_form.after_save = () => {
|
||||
setTimeout(() => {
|
||||
window.location.href = `/jobs`;
|
||||
})
|
||||
}
|
||||
})
|
||||
setTimeout(() => {
|
||||
window.location.href = `/jobs`;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def get_context(context):
|
||||
# do your magic here
|
||||
pass
|
||||
|
||||
226
lms/lms/api.py
226
lms/lms/api.py
@@ -3,161 +3,139 @@
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def autosave_section(section, code):
|
||||
"""Saves the code edited in one of the sections.
|
||||
"""
|
||||
doc = frappe.get_doc(
|
||||
doctype="Code Revision",
|
||||
section=section,
|
||||
code=code,
|
||||
author=frappe.session.user)
|
||||
doc.insert()
|
||||
return {"name": doc.name}
|
||||
"""Saves the code edited in one of the sections."""
|
||||
doc = frappe.get_doc(
|
||||
doctype="Code Revision", section=section, code=code, author=frappe.session.user
|
||||
)
|
||||
doc.insert()
|
||||
return {"name": doc.name}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def submit_solution(exercise, code):
|
||||
"""Submits a solution.
|
||||
"""Submits a solution.
|
||||
|
||||
@exerecise: name of the exercise to submit
|
||||
@code: solution to the exercise
|
||||
"""
|
||||
ex = frappe.get_doc("Exercise", exercise)
|
||||
if not ex:
|
||||
return
|
||||
doc = ex.submit(code)
|
||||
return {"name": doc.name, "creation": doc.creation}
|
||||
|
||||
@exerecise: name of the exercise to submit
|
||||
@code: solution to the exercise
|
||||
"""
|
||||
ex = frappe.get_doc("Exercise", exercise)
|
||||
if not ex:
|
||||
return
|
||||
doc = ex.submit(code)
|
||||
return {"name": doc.name, "creation": doc.creation}
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_current_lesson(course_name, lesson_name):
|
||||
"""Saves the current lesson for a student/mentor.
|
||||
"""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={
|
||||
"course": course_name,
|
||||
"member": frappe.session.user
|
||||
},
|
||||
fieldname="name")
|
||||
if not name:
|
||||
return
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.current_lesson = lesson_name
|
||||
doc.save(ignore_permissions=True)
|
||||
return {"current_lesson": doc.current_lesson}
|
||||
"""Saves the current lesson for a student/mentor."""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={"course": course_name, "member": frappe.session.user},
|
||||
fieldname="name",
|
||||
)
|
||||
if not name:
|
||||
return
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.current_lesson = lesson_name
|
||||
doc.save(ignore_permissions=True)
|
||||
return {"current_lesson": doc.current_lesson}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def join_cohort(course, cohort, subgroup, invite_code):
|
||||
"""Creates a Cohort Join Request for given user.
|
||||
"""
|
||||
course_doc = frappe.get_doc("LMS Course", course)
|
||||
cohort_doc = course_doc and course_doc.get_cohort(cohort)
|
||||
subgroup_doc = cohort_doc and cohort_doc.get_subgroup(subgroup)
|
||||
"""Creates a Cohort Join Request for given user."""
|
||||
course_doc = frappe.get_doc("LMS Course", course)
|
||||
cohort_doc = course_doc and course_doc.get_cohort(cohort)
|
||||
subgroup_doc = cohort_doc and cohort_doc.get_subgroup(subgroup)
|
||||
|
||||
if not subgroup_doc or subgroup_doc.invite_code != invite_code:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid join link"
|
||||
}
|
||||
if not subgroup_doc or subgroup_doc.invite_code != invite_code:
|
||||
return {"ok": False, "error": "Invalid join link"}
|
||||
|
||||
data = {
|
||||
"doctype": "Cohort Join Request",
|
||||
"cohort": cohort_doc.name,
|
||||
"subgroup": subgroup_doc.name,
|
||||
"email": frappe.session.user,
|
||||
"status": "Pending",
|
||||
}
|
||||
# Don't insert duplicate records
|
||||
if frappe.db.exists(data):
|
||||
return {"ok": True, "status": "record found"}
|
||||
else:
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
return {"ok": True, "status": "record created"}
|
||||
|
||||
data = {
|
||||
"doctype": "Cohort Join Request",
|
||||
"cohort": cohort_doc.name,
|
||||
"subgroup": subgroup_doc.name,
|
||||
"email": frappe.session.user,
|
||||
"status": "Pending"
|
||||
}
|
||||
# Don't insert duplicate records
|
||||
if frappe.db.exists(data):
|
||||
return {"ok": True, "status": "record found"}
|
||||
else:
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
return {"ok": True, "status": "record created"}
|
||||
|
||||
@frappe.whitelist()
|
||||
def approve_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Accepted"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Accepted"]:
|
||||
return {"ok": False, "error": "Invalid Join Request"}
|
||||
if (
|
||||
not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
|
||||
):
|
||||
return {"ok": False, "error": "Permission Deined"}
|
||||
|
||||
r.status = "Accepted"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
r.status = "Accepted"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
@frappe.whitelist()
|
||||
def reject_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {"ok": False, "error": "Invalid Join Request"}
|
||||
if (
|
||||
not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
|
||||
):
|
||||
return {"ok": False, "error": "Permission Deined"}
|
||||
|
||||
r.status = "Rejected"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
r.status = "Rejected"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def undo_reject_cohort_join_request(join_request):
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
# keeping Pending as well to consider the case of duplicate requests
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Invalid Join Request"
|
||||
}
|
||||
if not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
r = frappe.get_doc("Cohort Join Request", join_request)
|
||||
sg = r and frappe.get_doc("Cohort Subgroup", r.subgroup)
|
||||
# keeping Pending as well to consider the case of duplicate requests
|
||||
if not sg or r.status not in ["Pending", "Rejected"]:
|
||||
return {"ok": False, "error": "Invalid Join Request"}
|
||||
if (
|
||||
not sg.is_manager(frappe.session.user) and "System Manager" not in frappe.get_roles()
|
||||
):
|
||||
return {"ok": False, "error": "Permission Deined"}
|
||||
|
||||
r.status = "Pending"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
r.status = "Pending"
|
||||
r.save(ignore_permissions=True)
|
||||
return {"ok": True}
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_mentor_to_subgroup(subgroup, email):
|
||||
try:
|
||||
sg = frappe.get_doc("Cohort Subgroup", subgroup)
|
||||
except frappe.DoesNotExistError:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": f"Invalid subgroup: {subgroup}"
|
||||
}
|
||||
try:
|
||||
sg = frappe.get_doc("Cohort Subgroup", subgroup)
|
||||
except frappe.DoesNotExistError:
|
||||
return {"ok": False, "error": f"Invalid subgroup: {subgroup}"}
|
||||
|
||||
if not sg.get_cohort().is_admin(frappe.session.user) and "System Manager" not in frappe.get_roles():
|
||||
return {
|
||||
"ok": False,
|
||||
"error": "Permission Deined"
|
||||
}
|
||||
if (
|
||||
not sg.get_cohort().is_admin(frappe.session.user)
|
||||
and "System Manager" not in frappe.get_roles()
|
||||
):
|
||||
return {"ok": False, "error": "Permission Deined"}
|
||||
|
||||
try:
|
||||
user = frappe.get_doc("User", email)
|
||||
except frappe.DoesNotExistError:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": f"Invalid user: {email}"
|
||||
}
|
||||
try:
|
||||
user = frappe.get_doc("User", email)
|
||||
except frappe.DoesNotExistError:
|
||||
return {"ok": False, "error": f"Invalid user: {email}"}
|
||||
|
||||
sg.add_mentor(email)
|
||||
return {"ok": True}
|
||||
sg.add_mentor(email)
|
||||
return {"ok": True}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Certification', {
|
||||
frappe.ui.form.on("Certification", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class Certification(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCertification(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class ChapterReference(Document):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort', {
|
||||
frappe.ui.form.on("Cohort", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,82 +4,76 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class Cohort(Document):
|
||||
def get_url(self):
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/cohorts/{self.slug}"
|
||||
def get_url(self):
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/cohorts/{self.slug}"
|
||||
|
||||
def get_subgroups(self, include_counts=False, sort_by=None):
|
||||
names = frappe.get_all("Cohort Subgroup", filters={"cohort": self.name}, pluck="name")
|
||||
subgroups = [frappe.get_cached_doc("Cohort Subgroup", name) for name in names]
|
||||
subgroups = sorted(subgroups, key=lambda sg: sg.title)
|
||||
def get_subgroups(self, include_counts=False, sort_by=None):
|
||||
names = frappe.get_all("Cohort Subgroup", filters={"cohort": self.name}, pluck="name")
|
||||
subgroups = [frappe.get_cached_doc("Cohort Subgroup", name) for name in names]
|
||||
subgroups = sorted(subgroups, key=lambda sg: sg.title)
|
||||
|
||||
if include_counts:
|
||||
mentors = self._get_subgroup_counts("Cohort Mentor")
|
||||
students = self._get_subgroup_counts("LMS Batch Membership")
|
||||
join_requests = self._get_subgroup_counts("Cohort Join Request", status="Pending")
|
||||
for s in subgroups:
|
||||
s.num_mentors = mentors.get(s.name, 0)
|
||||
s.num_students = students.get(s.name, 0)
|
||||
s.num_join_requests = join_requests.get(s.name, 0)
|
||||
if include_counts:
|
||||
mentors = self._get_subgroup_counts("Cohort Mentor")
|
||||
students = self._get_subgroup_counts("LMS Batch Membership")
|
||||
join_requests = self._get_subgroup_counts("Cohort Join Request", status="Pending")
|
||||
for s in subgroups:
|
||||
s.num_mentors = mentors.get(s.name, 0)
|
||||
s.num_students = students.get(s.name, 0)
|
||||
s.num_join_requests = join_requests.get(s.name, 0)
|
||||
|
||||
if sort_by:
|
||||
subgroups.sort(key=lambda sg: getattr(sg, sort_by), reverse=True)
|
||||
return subgroups
|
||||
if sort_by:
|
||||
subgroups.sort(key=lambda sg: getattr(sg, sort_by), reverse=True)
|
||||
return subgroups
|
||||
|
||||
def _get_subgroup_counts(self, doctype, **kw):
|
||||
rows = frappe.get_all(doctype,
|
||||
filters={"cohort": self.name, **kw},
|
||||
fields=['subgroup', 'count(*) as count'],
|
||||
group_by='subgroup')
|
||||
return {row['subgroup']: row['count'] for row in rows}
|
||||
def _get_subgroup_counts(self, doctype, **kw):
|
||||
rows = frappe.get_all(
|
||||
doctype,
|
||||
filters={"cohort": self.name, **kw},
|
||||
fields=["subgroup", "count(*) as count"],
|
||||
group_by="subgroup",
|
||||
)
|
||||
return {row["subgroup"]: row["count"] for row in rows}
|
||||
|
||||
def _get_count(self, doctype, **kw):
|
||||
filters = {"cohort": self.name, **kw}
|
||||
return frappe.db.count(doctype, filters=filters)
|
||||
def _get_count(self, doctype, **kw):
|
||||
filters = {"cohort": self.name, **kw}
|
||||
return frappe.db.count(doctype, filters=filters)
|
||||
|
||||
def get_page_template(self, slug, scope=None):
|
||||
p = self.get_page(slug, scope=scope)
|
||||
return p and p.get_template_html()
|
||||
def get_page_template(self, slug, scope=None):
|
||||
p = self.get_page(slug, scope=scope)
|
||||
return p and p.get_template_html()
|
||||
|
||||
def get_page(self, slug, scope=None):
|
||||
for p in self.pages:
|
||||
if p.slug == slug and scope in [p.scope, None]:
|
||||
return p
|
||||
def get_page(self, slug, scope=None):
|
||||
for p in self.pages:
|
||||
if p.slug == slug and scope in [p.scope, None]:
|
||||
return p
|
||||
|
||||
def get_pages(self, scope=None):
|
||||
return [p for p in self.pages if scope in [p.scope, None]]
|
||||
def get_pages(self, scope=None):
|
||||
return [p for p in self.pages if scope in [p.scope, None]]
|
||||
|
||||
def get_stats(self):
|
||||
return {
|
||||
"subgroups": self._get_count("Cohort Subgroup"),
|
||||
"mentors": self._get_count("Cohort Mentor"),
|
||||
"students": self._get_count("LMS Batch Membership"),
|
||||
"join_requests": self._get_count("Cohort Join Request", status="Pending"),
|
||||
}
|
||||
def get_stats(self):
|
||||
return {
|
||||
"subgroups": self._get_count("Cohort Subgroup"),
|
||||
"mentors": self._get_count("Cohort Mentor"),
|
||||
"students": self._get_count("LMS Batch Membership"),
|
||||
"join_requests": self._get_count("Cohort Join Request", status="Pending"),
|
||||
}
|
||||
|
||||
def get_subgroup(self, slug):
|
||||
q = dict(cohort=self.name, slug=slug)
|
||||
name = frappe.db.get_value("Cohort Subgroup", q, "name")
|
||||
return name and frappe.get_doc("Cohort Subgroup", name)
|
||||
def get_subgroup(self, slug):
|
||||
q = dict(cohort=self.name, slug=slug)
|
||||
name = frappe.db.get_value("Cohort Subgroup", q, "name")
|
||||
return name and frappe.get_doc("Cohort Subgroup", name)
|
||||
|
||||
def get_mentor(self, email):
|
||||
q = dict(cohort=self.name, email=email)
|
||||
name = frappe.db.get_value("Cohort Mentor", q, "name")
|
||||
return name and frappe.get_doc("Cohort Mentor", name)
|
||||
def get_mentor(self, email):
|
||||
q = dict(cohort=self.name, email=email)
|
||||
name = frappe.db.get_value("Cohort Mentor", q, "name")
|
||||
return name and frappe.get_doc("Cohort Mentor", name)
|
||||
|
||||
def is_mentor(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"cohort": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
def is_mentor(self, email):
|
||||
q = {"doctype": "Cohort Mentor", "cohort": self.name, "email": email}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def is_admin(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Staff",
|
||||
"cohort": self.name,
|
||||
"email": email,
|
||||
"role": "Admin"
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
def is_admin(self, email):
|
||||
q = {"doctype": "Cohort Staff", "cohort": self.name, "email": email, "role": "Admin"}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCohort(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Join Request', {
|
||||
frappe.ui.form.on("Cohort Join Request", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,48 +4,49 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CohortJoinRequest(Document):
|
||||
def on_update(self):
|
||||
if self.status == "Accepted":
|
||||
self.ensure_student()
|
||||
def on_update(self):
|
||||
if self.status == "Accepted":
|
||||
self.ensure_student()
|
||||
|
||||
def ensure_student(self):
|
||||
# case 1 - user is already a member
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student"
|
||||
}
|
||||
if frappe.db.exists(q):
|
||||
return
|
||||
def ensure_student(self):
|
||||
# case 1 - user is already a member
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student",
|
||||
}
|
||||
if frappe.db.exists(q):
|
||||
return
|
||||
|
||||
# case 2 - user has signed up for this course, possibly not this cohort
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
# case 2 - user has signed up for this course, possibly not this cohort
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"member": self.email,
|
||||
"member_type": "Student"
|
||||
}
|
||||
name = frappe.db.exists(q)
|
||||
if name:
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.cohort = self.cohort
|
||||
doc.subgroup = self.subgroup
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
# case 3 - user has not signed up for this course yet
|
||||
data = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student",
|
||||
"role": "Member"
|
||||
}
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"member": self.email,
|
||||
"member_type": "Student",
|
||||
}
|
||||
name = frappe.db.exists(q)
|
||||
if name:
|
||||
doc = frappe.get_doc("LMS Batch Membership", name)
|
||||
doc.cohort = self.cohort
|
||||
doc.subgroup = self.subgroup
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
# case 3 - user has not signed up for this course yet
|
||||
data = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": cohort.course,
|
||||
"cohort": self.cohort,
|
||||
"subgroup": self.subgroup,
|
||||
"member": self.email,
|
||||
"member_type": "Student",
|
||||
"role": "Member",
|
||||
}
|
||||
doc = frappe.get_doc(data)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCohortJoinRequest(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Mentor', {
|
||||
frappe.ui.form.on("Cohort Mentor", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CohortMentor(Document):
|
||||
def get_subgroup(self):
|
||||
return frappe.get_doc("Cohort Subgroup", self.subgroup)
|
||||
|
||||
def get_user(self):
|
||||
return frappe.get_doc("User", self.email)
|
||||
class CohortMentor(Document):
|
||||
def get_subgroup(self):
|
||||
return frappe.get_doc("Cohort Subgroup", self.subgroup)
|
||||
|
||||
def get_user(self):
|
||||
return frappe.get_doc("User", self.email)
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCohortMentor(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Staff', {
|
||||
frappe.ui.form.on("Cohort Staff", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CohortStaff(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCohortStaff(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Cohort Subgroup', {
|
||||
frappe.ui.form.on("Cohort Subgroup", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -5,91 +5,84 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import random_string
|
||||
|
||||
|
||||
class CohortSubgroup(Document):
|
||||
def before_save(self):
|
||||
if not self.invite_code:
|
||||
self.invite_code = random_string(8)
|
||||
def before_save(self):
|
||||
if not self.invite_code:
|
||||
self.invite_code = random_string(8)
|
||||
|
||||
def get_url(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/subgroups/{cohort.slug}/{self.slug}"
|
||||
def get_url(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return (
|
||||
f"{frappe.utils.get_url()}/courses/{self.course}/subgroups/{cohort.slug}/{self.slug}"
|
||||
)
|
||||
|
||||
def get_invite_link(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/join/{cohort.slug}/{self.slug}/{self.invite_code}"
|
||||
def get_invite_link(self):
|
||||
cohort = frappe.get_doc("Cohort", self.cohort)
|
||||
return f"{frappe.utils.get_url()}/courses/{self.course}/join/{cohort.slug}/{self.slug}/{self.invite_code}"
|
||||
|
||||
def has_student(self, email):
|
||||
"""Check if given user is a student of this subgroup.
|
||||
"""
|
||||
q = {
|
||||
"doctype": "LMS Batch Membership",
|
||||
"subgroup": self.name,
|
||||
"member": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
def has_student(self, email):
|
||||
"""Check if given user is a student of this subgroup."""
|
||||
q = {"doctype": "LMS Batch Membership", "subgroup": self.name, "member": email}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def has_join_request(self, email):
|
||||
"""Check if given user is a student of this subgroup.
|
||||
"""
|
||||
q = {
|
||||
"doctype": "Cohort Join Request",
|
||||
"subgroup": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
def has_join_request(self, email):
|
||||
"""Check if given user is a student of this subgroup."""
|
||||
q = {"doctype": "Cohort Join Request", "subgroup": self.name, "email": email}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def get_join_requests(self, status="Pending"):
|
||||
q = {
|
||||
"subgroup": self.name,
|
||||
"status": status
|
||||
}
|
||||
return frappe.get_all("Cohort Join Request", filters=q, fields=["*"], order_by="creation desc")
|
||||
def get_join_requests(self, status="Pending"):
|
||||
q = {"subgroup": self.name, "status": status}
|
||||
return frappe.get_all(
|
||||
"Cohort Join Request", filters=q, fields=["*"], order_by="creation desc"
|
||||
)
|
||||
|
||||
def get_mentors(self):
|
||||
emails = frappe.get_all("Cohort Mentor", filters={"subgroup": self.name}, fields=["email"], pluck='email')
|
||||
return self._get_users(emails)
|
||||
def get_mentors(self):
|
||||
emails = frappe.get_all(
|
||||
"Cohort Mentor", filters={"subgroup": self.name}, fields=["email"], pluck="email"
|
||||
)
|
||||
return self._get_users(emails)
|
||||
|
||||
def get_students(self):
|
||||
emails = frappe.get_all("LMS Batch Membership",
|
||||
filters={"subgroup": self.name},
|
||||
fields=["member"],
|
||||
pluck='member',
|
||||
page_length=1000)
|
||||
return self._get_users(emails)
|
||||
def get_students(self):
|
||||
emails = frappe.get_all(
|
||||
"LMS Batch Membership",
|
||||
filters={"subgroup": self.name},
|
||||
fields=["member"],
|
||||
pluck="member",
|
||||
page_length=1000,
|
||||
)
|
||||
return self._get_users(emails)
|
||||
|
||||
def _get_users(self, emails):
|
||||
users = [frappe.get_cached_doc("User", email) for email in emails]
|
||||
return sorted(users, key=lambda user: user.full_name)
|
||||
def _get_users(self, emails):
|
||||
users = [frappe.get_cached_doc("User", email) for email in emails]
|
||||
return sorted(users, key=lambda user: user.full_name)
|
||||
|
||||
def is_mentor(self, email):
|
||||
q = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"subgroup": self.name,
|
||||
"email": email
|
||||
}
|
||||
return frappe.db.exists(q)
|
||||
def is_mentor(self, email):
|
||||
q = {"doctype": "Cohort Mentor", "subgroup": self.name, "email": email}
|
||||
return frappe.db.exists(q)
|
||||
|
||||
def is_manager(self, email):
|
||||
"""Returns True if the given user is a manager of this subgroup.
|
||||
def is_manager(self, email):
|
||||
"""Returns True if the given user is a manager of this subgroup.
|
||||
|
||||
Mentors of the subgroup, admins of the Cohort are considered as managers.
|
||||
"""
|
||||
return self.is_mentor(email) or self.get_cohort().is_admin(email)
|
||||
Mentors of the subgroup, admins of the Cohort are considered as managers.
|
||||
"""
|
||||
return self.is_mentor(email) or self.get_cohort().is_admin(email)
|
||||
|
||||
def get_cohort(self):
|
||||
return frappe.get_doc("Cohort", self.cohort)
|
||||
def get_cohort(self):
|
||||
return frappe.get_doc("Cohort", self.cohort)
|
||||
|
||||
def add_mentor(self, email):
|
||||
d = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"subgroup": self.name,
|
||||
"cohort": self.cohort,
|
||||
"email": email
|
||||
}
|
||||
if frappe.db.exists(d):
|
||||
return
|
||||
doc = frappe.get_doc(d)
|
||||
doc.insert(ignore_permissions=True)
|
||||
def add_mentor(self, email):
|
||||
d = {
|
||||
"doctype": "Cohort Mentor",
|
||||
"subgroup": self.name,
|
||||
"cohort": self.cohort,
|
||||
"email": email,
|
||||
}
|
||||
if frappe.db.exists(d):
|
||||
return
|
||||
doc = frappe.get_doc(d)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
#def after_doctype_insert():
|
||||
|
||||
# def after_doctype_insert():
|
||||
# frappe.db.add_unique("Cohort Subgroup", ("cohort", "slug"))
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCohortSubgroup(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CohortWebPage(Document):
|
||||
def get_template_html(self):
|
||||
return frappe.get_doc("Web Template", self.template).template
|
||||
def get_template_html(self):
|
||||
return frappe.get_doc("Web Template", self.template).template
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Course Chapter', {
|
||||
frappe.ui.form.on("Course Chapter", {
|
||||
onload: function (frm) {
|
||||
frm.set_query("lesson", "lessons", function () {
|
||||
return {
|
||||
filters: {
|
||||
"chapter": frm.doc.name,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
frm.set_query("lesson", "lessons", function () {
|
||||
return {
|
||||
filters: {
|
||||
chapter: frm.doc.name,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CourseChapter(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCourseChapter(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// Copyright (c) 2022, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Course Evaluator', {
|
||||
onload: (frm) => {
|
||||
frm.set_query('evaluator', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
frappe.ui.form.on("Course Evaluator", {
|
||||
onload: (frm) => {
|
||||
frm.set_query("evaluator", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,46 +5,53 @@ import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CourseEvaluator(Document):
|
||||
def validate(self):
|
||||
self.validate_time_slots()
|
||||
|
||||
def validate(self):
|
||||
self.validate_time_slots()
|
||||
def validate_time_slots(self):
|
||||
for schedule in self.schedule:
|
||||
if schedule.start_time >= schedule.end_time:
|
||||
frappe.throw(_("Start Time cannot be greater than End Time"))
|
||||
|
||||
def validate_time_slots(self):
|
||||
for schedule in self.schedule:
|
||||
if schedule.start_time >= schedule.end_time:
|
||||
frappe.throw(_("Start Time cannot be greater than End Time"))
|
||||
self.validate_overlaps(schedule)
|
||||
|
||||
self.validate_overlaps(schedule)
|
||||
def validate_overlaps(self, schedule):
|
||||
same_day_slots = list(
|
||||
filter(lambda x: x.day == schedule.day and x.name != schedule.name, self.schedule)
|
||||
)
|
||||
overlap = False
|
||||
|
||||
def validate_overlaps(self, schedule):
|
||||
same_day_slots = list(filter(lambda x: x.day == schedule.day and x.name != schedule.name , self.schedule))
|
||||
overlap = False
|
||||
for slot in same_day_slots:
|
||||
if schedule.start_time <= slot.start_time < schedule.end_time:
|
||||
overlap = True
|
||||
if schedule.start_time < slot.end_time <= schedule.end_time:
|
||||
overlap = True
|
||||
if slot.start_time < schedule.start_time and schedule.end_time < slot.end_time:
|
||||
overlap = True
|
||||
|
||||
for slot in same_day_slots:
|
||||
if schedule.start_time <= slot.start_time < schedule.end_time:
|
||||
overlap = True
|
||||
if schedule.start_time < slot.end_time <= schedule.end_time:
|
||||
overlap = True
|
||||
if slot.start_time < schedule.start_time and schedule.end_time < slot.end_time:
|
||||
overlap = True
|
||||
if overlap:
|
||||
frappe.throw(_("Slot Times are overlapping for some schedules."))
|
||||
|
||||
if overlap:
|
||||
frappe.throw(_("Slot Times are overlapping for some schedules."))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_schedule(course, date):
|
||||
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
||||
all_slots = frappe.get_all("Evaluator Schedule",
|
||||
filters = { "parent": evaluator },
|
||||
fields = ["day", "start_time", "end_time"])
|
||||
booked_slots = frappe.get_all("LMS Certificate Request",
|
||||
filters = {"evaluator": evaluator, "date": date},
|
||||
fields = ["start_time"])
|
||||
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
||||
all_slots = frappe.get_all(
|
||||
"Evaluator Schedule",
|
||||
filters={"parent": evaluator},
|
||||
fields=["day", "start_time", "end_time"],
|
||||
)
|
||||
booked_slots = frappe.get_all(
|
||||
"LMS Certificate Request",
|
||||
filters={"evaluator": evaluator, "date": date},
|
||||
fields=["start_time"],
|
||||
)
|
||||
|
||||
for slot in booked_slots:
|
||||
same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots))
|
||||
if len(same_slot):
|
||||
all_slots.remove(same_slot[0])
|
||||
for slot in booked_slots:
|
||||
same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots))
|
||||
if len(same_slot):
|
||||
all_slots.remove(same_slot[0])
|
||||
|
||||
return all_slots
|
||||
return all_slots
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class CourseInstructor(Document):
|
||||
pass
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Course Lesson', {
|
||||
setup: function (frm) {
|
||||
frm.trigger('setup_help');
|
||||
},
|
||||
setup_help(frm) {
|
||||
let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`;
|
||||
let exercise_link = `<a href="/app/exercise"> ${__("Exercise List")} </a>`;
|
||||
let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`;
|
||||
frappe.ui.form.on("Course Lesson", {
|
||||
setup: function (frm) {
|
||||
frm.trigger("setup_help");
|
||||
},
|
||||
setup_help(frm) {
|
||||
let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`;
|
||||
let exercise_link = `<a href="/app/exercise"> ${__(
|
||||
"Exercise List"
|
||||
)} </a>`;
|
||||
let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`;
|
||||
|
||||
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>
|
||||
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>
|
||||
<table class="table">
|
||||
<tr style="background-color: var(--fg-hover-color); font-weight: bold">
|
||||
<th style="width: 20%;">
|
||||
@@ -33,17 +37,23 @@ frappe.ui.form.on('Course Lesson', {
|
||||
</td>
|
||||
<td>
|
||||
<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>
|
||||
<ul class="p-4">
|
||||
<li>
|
||||
${ __("Upload the video on youtube.") }
|
||||
${__("Upload the video on youtube.")}
|
||||
</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>
|
||||
${ __("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>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -56,7 +66,10 @@ frappe.ui.form.on('Course Lesson', {
|
||||
{{ Quiz("lms_quiz_id") }}
|
||||
</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>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -67,7 +80,10 @@ frappe.ui.form.on('Course Lesson', {
|
||||
{{ Video("url_of_source") }}
|
||||
</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>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -78,7 +94,10 @@ frappe.ui.form.on('Course Lesson', {
|
||||
{{ Exercise("exercise_id") }}
|
||||
</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>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -125,5 +144,5 @@ frappe.ui.form.on('Course Lesson', {
|
||||
</tr>
|
||||
</table>
|
||||
`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,125 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from ...md import find_macros
|
||||
|
||||
from lms.lms.utils import get_course_progress, get_lesson_url
|
||||
|
||||
from ...md import find_macros
|
||||
|
||||
|
||||
class CourseLesson(Document):
|
||||
def validate(self):
|
||||
#self.check_and_create_folder()
|
||||
self.validate_quiz_id()
|
||||
def validate(self):
|
||||
# self.check_and_create_folder()
|
||||
self.validate_quiz_id()
|
||||
|
||||
def validate_quiz_id(self):
|
||||
if self.quiz_id and not frappe.db.exists("LMS Quiz", self.quiz_id):
|
||||
frappe.throw(_("Invalid Quiz ID"))
|
||||
|
||||
def validate_quiz_id(self):
|
||||
if self.quiz_id and not frappe.db.exists("LMS Quiz", self.quiz_id):
|
||||
frappe.throw(_("Invalid Quiz ID"))
|
||||
def on_update(self):
|
||||
dynamic_documents = ["Exercise", "Quiz"]
|
||||
for section in dynamic_documents:
|
||||
self.update_lesson_name_in_document(section)
|
||||
|
||||
def update_lesson_name_in_document(self, section):
|
||||
doctype_map = {"Exercise": "Exercise", "Quiz": "LMS Quiz"}
|
||||
macros = find_macros(self.body)
|
||||
documents = [value for name, value in macros if name == section]
|
||||
index = 1
|
||||
for name in documents:
|
||||
e = frappe.get_doc(doctype_map[section], name)
|
||||
e.lesson = self.name
|
||||
e.index_ = index
|
||||
e.save(ignore_permissions=True)
|
||||
index += 1
|
||||
self.update_orphan_documents(doctype_map[section], documents)
|
||||
|
||||
def on_update(self):
|
||||
dynamic_documents = ["Exercise", "Quiz"]
|
||||
for section in dynamic_documents:
|
||||
self.update_lesson_name_in_document(section)
|
||||
def update_orphan_documents(self, doctype, documents):
|
||||
"""Updates the documents that were previously part of this lesson,
|
||||
but not any more.
|
||||
"""
|
||||
linked_documents = {
|
||||
row["name"] for row in frappe.get_all(doctype, {"lesson": self.name})
|
||||
}
|
||||
active_documents = set(documents)
|
||||
orphan_documents = linked_documents - active_documents
|
||||
for name in orphan_documents:
|
||||
ex = frappe.get_doc(doctype, name)
|
||||
ex.lesson = None
|
||||
ex.index_ = 0
|
||||
ex.index_label = ""
|
||||
ex.save()
|
||||
|
||||
def check_and_create_folder(self):
|
||||
args = {
|
||||
"doctype": "File",
|
||||
"is_folder": True,
|
||||
"file_name": f"{self.name} {self.course}",
|
||||
}
|
||||
if not frappe.db.exists(args):
|
||||
folder = frappe.get_doc(args)
|
||||
folder.save(ignore_permissions=True)
|
||||
|
||||
def update_lesson_name_in_document(self, section):
|
||||
doctype_map= {
|
||||
"Exercise": "Exercise",
|
||||
"Quiz": "LMS Quiz"
|
||||
}
|
||||
macros = find_macros(self.body)
|
||||
documents = [value for name, value in macros if name == section]
|
||||
index = 1
|
||||
for name in documents:
|
||||
e = frappe.get_doc(doctype_map[section], name)
|
||||
e.lesson = self.name
|
||||
e.index_ = index
|
||||
e.save(ignore_permissions=True)
|
||||
index += 1
|
||||
self.update_orphan_documents(doctype_map[section], documents)
|
||||
def get_exercises(self):
|
||||
if not self.body:
|
||||
return []
|
||||
|
||||
macros = find_macros(self.body)
|
||||
exercises = [value for name, value in macros if name == "Exercise"]
|
||||
return [frappe.get_doc("Exercise", name) for name in exercises]
|
||||
|
||||
def update_orphan_documents(self, doctype, documents):
|
||||
"""Updates the documents that were previously part of this lesson,
|
||||
but not any more.
|
||||
"""
|
||||
linked_documents = {row['name'] for row in frappe.get_all(doctype, {"lesson": self.name})}
|
||||
active_documents = set(documents)
|
||||
orphan_documents = linked_documents - active_documents
|
||||
for name in orphan_documents:
|
||||
ex = frappe.get_doc(doctype, name)
|
||||
ex.lesson = None
|
||||
ex.index_ = 0
|
||||
ex.index_label = ""
|
||||
ex.save()
|
||||
def get_progress(self):
|
||||
return frappe.db.get_value(
|
||||
"LMS Course Progress", {"lesson": self.name, "owner": frappe.session.user}, "status"
|
||||
)
|
||||
|
||||
|
||||
def check_and_create_folder(self):
|
||||
args = {
|
||||
"doctype": "File",
|
||||
"is_folder": True,
|
||||
"file_name": f"{self.name} {self.course}"
|
||||
}
|
||||
if not frappe.db.exists(args):
|
||||
folder = frappe.get_doc(args)
|
||||
folder.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def get_exercises(self):
|
||||
if not self.body:
|
||||
return []
|
||||
|
||||
macros = find_macros(self.body)
|
||||
exercises = [value for name, value in macros if name == "Exercise"]
|
||||
return [frappe.get_doc("Exercise", name) for name in exercises]
|
||||
|
||||
def get_progress(self):
|
||||
return frappe.db.get_value("LMS Course Progress", {"lesson": self.name, "owner": frappe.session.user}, "status")
|
||||
|
||||
def get_slugified_class(self):
|
||||
if self.get_progress():
|
||||
return ("").join([ s for s in self.get_progress().lower().split() ])
|
||||
return
|
||||
def get_slugified_class(self):
|
||||
if self.get_progress():
|
||||
return ("").join([s for s in self.get_progress().lower().split()])
|
||||
return
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_progress(lesson, course, status):
|
||||
membership = frappe.db.exists("LMS Batch Membership", {
|
||||
"member": frappe.session.user,
|
||||
"course": course
|
||||
})
|
||||
if not membership:
|
||||
return
|
||||
membership = frappe.db.exists(
|
||||
"LMS Batch Membership", {"member": frappe.session.user, "course": course}
|
||||
)
|
||||
if not membership:
|
||||
return
|
||||
|
||||
if frappe.db.exists("LMS Course Progress", {
|
||||
"lesson": lesson,
|
||||
"owner": frappe.session.user,
|
||||
"course": course
|
||||
}):
|
||||
doc = frappe.get_doc("LMS Course Progress", {
|
||||
"lesson": lesson,
|
||||
"owner": frappe.session.user,
|
||||
"course": course
|
||||
})
|
||||
doc.status = status
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
frappe.get_doc({
|
||||
"doctype": "LMS Course Progress",
|
||||
"lesson": lesson,
|
||||
"status": status,
|
||||
}).save(ignore_permissions=True)
|
||||
if frappe.db.exists(
|
||||
"LMS Course Progress",
|
||||
{"lesson": lesson, "owner": frappe.session.user, "course": course},
|
||||
):
|
||||
doc = frappe.get_doc(
|
||||
"LMS Course Progress",
|
||||
{"lesson": lesson, "owner": frappe.session.user, "course": course},
|
||||
)
|
||||
doc.status = status
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Course Progress",
|
||||
"lesson": lesson,
|
||||
"status": status,
|
||||
}
|
||||
).save(ignore_permissions=True)
|
||||
|
||||
progress = get_course_progress(course)
|
||||
frappe.db.set_value("LMS Batch Membership", membership, "progress", progress)
|
||||
return progress
|
||||
progress = get_course_progress(course)
|
||||
frappe.db.set_value("LMS Batch Membership", membership, "progress", progress)
|
||||
return progress
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_lesson_info(chapter):
|
||||
return frappe.db.get_value("Course Chapter", chapter, "course")
|
||||
return frappe.db.get_value("Course Chapter", chapter, "course")
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCourseLesson(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class EducationDetail(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class EvaluatorSchedule(Document):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise', {
|
||||
frappe.ui.form.on("Exercise", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -3,51 +3,50 @@
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
from lms.lms.utils import get_membership
|
||||
|
||||
|
||||
class Exercise(Document):
|
||||
def get_user_submission(self):
|
||||
"""Returns the latest submission for this user.
|
||||
"""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
def get_user_submission(self):
|
||||
"""Returns the latest submission for this user."""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
|
||||
result = frappe.get_all('Exercise Submission',
|
||||
fields="*",
|
||||
filters={
|
||||
"owner": user,
|
||||
"exercise": self.name
|
||||
},
|
||||
order_by="creation desc",
|
||||
page_length=1)
|
||||
result = frappe.get_all(
|
||||
"Exercise Submission",
|
||||
fields="*",
|
||||
filters={"owner": user, "exercise": self.name},
|
||||
order_by="creation desc",
|
||||
page_length=1,
|
||||
)
|
||||
|
||||
if result:
|
||||
return result[0]
|
||||
if result:
|
||||
return result[0]
|
||||
|
||||
def submit(self, code):
|
||||
"""Submits the given code as solution to exercise.
|
||||
"""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
def submit(self, code):
|
||||
"""Submits the given code as solution to exercise."""
|
||||
user = frappe.session.user
|
||||
if not user or user == "Guest":
|
||||
return
|
||||
|
||||
old_submission = self.get_user_submission()
|
||||
if old_submission and old_submission.solution == code:
|
||||
return old_submission
|
||||
old_submission = self.get_user_submission()
|
||||
if old_submission and old_submission.solution == code:
|
||||
return old_submission
|
||||
|
||||
member = get_membership(self.course, frappe.session.user)
|
||||
member = get_membership(self.course, frappe.session.user)
|
||||
|
||||
doc = frappe.get_doc(
|
||||
doctype="Exercise Submission",
|
||||
exercise=self.name,
|
||||
exercise_title=self.title,
|
||||
course=self.course,
|
||||
lesson=self.lesson,
|
||||
batch=member.batch,
|
||||
solution=code,
|
||||
member=member.name)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
return doc
|
||||
doc = frappe.get_doc(
|
||||
doctype="Exercise Submission",
|
||||
exercise=self.name,
|
||||
exercise_title=self.title,
|
||||
course=self.course,
|
||||
lesson=self.lesson,
|
||||
batch=member.batch,
|
||||
solution=code,
|
||||
member=member.name,
|
||||
)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
return doc
|
||||
|
||||
@@ -1,50 +1,54 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from lms.lms.doctype.lms_course.test_lms_course import new_course
|
||||
|
||||
|
||||
class TestExercise(unittest.TestCase):
|
||||
def new_exercise(self):
|
||||
course = new_course("Test Course")
|
||||
member = frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": course.name,
|
||||
"member": frappe.session.user,
|
||||
}
|
||||
)
|
||||
member.insert()
|
||||
e = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Exercise",
|
||||
"name": "test-problem",
|
||||
"course": course.name,
|
||||
"title": "Test Problem",
|
||||
"description": "draw a circle",
|
||||
"code": "# draw a single cicle",
|
||||
"answer": ("# draw a single circle\n" + "circle(100, 100, 50)"),
|
||||
}
|
||||
)
|
||||
e.insert()
|
||||
return e
|
||||
|
||||
def new_exercise(self):
|
||||
course = new_course("Test Course")
|
||||
member = frappe.get_doc({
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": course.name,
|
||||
"member": frappe.session.user
|
||||
})
|
||||
member.insert()
|
||||
e = frappe.get_doc({
|
||||
"doctype": "Exercise",
|
||||
"name": "test-problem",
|
||||
"course": course.name,
|
||||
"title": "Test Problem",
|
||||
"description": "draw a circle",
|
||||
"code": "# draw a single cicle",
|
||||
"answer": (
|
||||
"# draw a single circle\n" +
|
||||
"circle(100, 100, 50)")
|
||||
})
|
||||
e.insert()
|
||||
return e
|
||||
def test_exercise(self):
|
||||
e = self.new_exercise()
|
||||
assert e.get_user_submission() is None
|
||||
|
||||
def test_exercise(self):
|
||||
e = self.new_exercise()
|
||||
assert e.get_user_submission() is None
|
||||
def test_exercise_submission(self):
|
||||
e = self.new_exercise()
|
||||
submission = e.submit("circle(100, 100, 50)")
|
||||
assert submission is not None
|
||||
assert submission.exercise == e.name
|
||||
assert submission.course == e.course
|
||||
|
||||
def test_exercise_submission(self):
|
||||
e = self.new_exercise()
|
||||
submission = e.submit("circle(100, 100, 50)")
|
||||
assert submission is not None
|
||||
assert submission.exercise == e.name
|
||||
assert submission.course == e.course
|
||||
user_submission = e.get_user_submission()
|
||||
assert user_submission is not None
|
||||
assert user_submission.name == submission.name
|
||||
|
||||
user_submission = e.get_user_submission()
|
||||
assert user_submission is not None
|
||||
assert user_submission.name == submission.name
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.sql('delete from `tabLMS Batch Membership`')
|
||||
frappe.db.sql('delete from `tabExercise Submission`')
|
||||
frappe.db.sql('delete from `tabExercise`')
|
||||
def tearDown(self):
|
||||
frappe.db.sql("delete from `tabLMS Batch Membership`")
|
||||
frappe.db.sql("delete from `tabExercise Submission`")
|
||||
frappe.db.sql("delete from `tabExercise`")
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise Latest Submission', {
|
||||
frappe.ui.form.on("Exercise Latest Submission", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class ExerciseLatestSubmission(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestExerciseLatestSubmission(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise Submission', {
|
||||
frappe.ui.form.on("Exercise Submission", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,21 +4,26 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ExerciseSubmission(Document):
|
||||
def on_update(self):
|
||||
self.update_latest_submission()
|
||||
|
||||
def update_latest_submission(self):
|
||||
names = frappe.get_all("Exercise Latest Submission", {"exercise": self.exercise, "member": self.member})
|
||||
if names:
|
||||
doc = frappe.get_doc("Exercise Latest Submission", names[0])
|
||||
doc.latest_submission = self.name
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Exercise Latest Submission",
|
||||
"exercise": self.exercise,
|
||||
"member": self.member,
|
||||
"latest_submission": self.name
|
||||
})
|
||||
doc.insert(ignore_permissions=True)
|
||||
class ExerciseSubmission(Document):
|
||||
def on_update(self):
|
||||
self.update_latest_submission()
|
||||
|
||||
def update_latest_submission(self):
|
||||
names = frappe.get_all(
|
||||
"Exercise Latest Submission", {"exercise": self.exercise, "member": self.member}
|
||||
)
|
||||
if names:
|
||||
doc = frappe.get_doc("Exercise Latest Submission", names[0])
|
||||
doc.latest_submission = self.name
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Exercise Latest Submission",
|
||||
"exercise": self.exercise,
|
||||
"member": self.member,
|
||||
"latest_submission": self.name,
|
||||
}
|
||||
)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestExerciseSubmission(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Function', {
|
||||
frappe.ui.form.on("Function", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class Function(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestFunction(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Industry', {
|
||||
frappe.ui.form.on("Industry", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class Industry(Document):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestIndustry(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Invite Request', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
frappe.ui.form.on("Invite Request", {
|
||||
// refresh: function(frm) {
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -1,90 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
import json
|
||||
from frappe.utils.password import get_decrypted_password
|
||||
|
||||
|
||||
class InviteRequest(Document):
|
||||
def on_update(self):
|
||||
if self.has_value_changed("status") and self.status == "Approved":
|
||||
self.send_email()
|
||||
def on_update(self):
|
||||
if self.has_value_changed("status") and self.status == "Approved":
|
||||
self.send_email()
|
||||
|
||||
def create_user(self, password):
|
||||
full_name_split = self.full_name.split(" ")
|
||||
user = frappe.get_doc({
|
||||
"doctype": "User",
|
||||
"email": self.signup_email,
|
||||
"first_name": full_name_split[0],
|
||||
"last_name": full_name_split[1] if len(full_name_split) > 1 else "",
|
||||
"username": self.username,
|
||||
"send_welcome_email": 0,
|
||||
"user_type": "Website User",
|
||||
"new_password": password
|
||||
})
|
||||
user.save(ignore_permissions=True)
|
||||
return user
|
||||
def create_user(self, password):
|
||||
full_name_split = self.full_name.split(" ")
|
||||
user = frappe.get_doc(
|
||||
{
|
||||
"doctype": "User",
|
||||
"email": self.signup_email,
|
||||
"first_name": full_name_split[0],
|
||||
"last_name": full_name_split[1] if len(full_name_split) > 1 else "",
|
||||
"username": self.username,
|
||||
"send_welcome_email": 0,
|
||||
"user_type": "Website User",
|
||||
"new_password": password,
|
||||
}
|
||||
)
|
||||
user.save(ignore_permissions=True)
|
||||
return user
|
||||
|
||||
def send_email(self):
|
||||
site_name = "Mon.School"
|
||||
subject = _("Welcome to {0}!").format(site_name)
|
||||
def send_email(self):
|
||||
site_name = "Mon.School"
|
||||
subject = _("Welcome to {0}!").format(site_name)
|
||||
|
||||
args = {
|
||||
"full_name": self.full_name,
|
||||
"signup_form_link": f"/new-sign-up?invite_code={self.name}",
|
||||
"site_name": site_name,
|
||||
"site_url": frappe.utils.get_url(),
|
||||
}
|
||||
frappe.sendmail(
|
||||
recipients=self.invite_email,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template="lms_invite_request_approved",
|
||||
args=args,
|
||||
now=True,
|
||||
)
|
||||
|
||||
args = {
|
||||
"full_name": self.full_name,
|
||||
"signup_form_link": "/new-sign-up?invite_code={0}".format(self.name),
|
||||
"site_name": site_name,
|
||||
"site_url": frappe.utils.get_url()
|
||||
}
|
||||
frappe.sendmail(
|
||||
recipients=self.invite_email,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template = "lms_invite_request_approved",
|
||||
args=args,
|
||||
now=True)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def create_invite_request(invite_email):
|
||||
|
||||
if not frappe.utils.validate_email_address(invite_email):
|
||||
return "invalid email"
|
||||
if not frappe.utils.validate_email_address(invite_email):
|
||||
return "invalid email"
|
||||
|
||||
if frappe.db.exists("User", invite_email):
|
||||
return "user"
|
||||
if frappe.db.exists("User", invite_email):
|
||||
return "user"
|
||||
|
||||
if frappe.db.exists("Invite Request", {"invite_email": invite_email}):
|
||||
return "invite"
|
||||
if frappe.db.exists("Invite Request", {"invite_email": invite_email}):
|
||||
return "invite"
|
||||
|
||||
frappe.get_doc({
|
||||
"doctype": "Invite Request",
|
||||
"invite_email": invite_email,
|
||||
"status": "Approved"
|
||||
}).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
frappe.get_doc(
|
||||
{"doctype": "Invite Request", "invite_email": invite_email, "status": "Approved"}
|
||||
).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def update_invite(data):
|
||||
data = frappe._dict(json.loads(data)) if type(data) == str else frappe._dict(data)
|
||||
data = frappe._dict(json.loads(data)) if type(data) == str else frappe._dict(data)
|
||||
|
||||
try:
|
||||
doc = frappe.get_doc("Invite Request", data.invite_code)
|
||||
except frappe.DoesNotExistError:
|
||||
frappe.throw(_("Invalid Invite Code."))
|
||||
try:
|
||||
doc = frappe.get_doc("Invite Request", data.invite_code)
|
||||
except frappe.DoesNotExistError:
|
||||
frappe.throw(_("Invalid Invite Code."))
|
||||
|
||||
doc.signup_email = data.signup_email
|
||||
doc.username = data.username
|
||||
doc.full_name = data.full_name
|
||||
doc.invite_code = data.invite_code
|
||||
doc.save(ignore_permissions=True)
|
||||
doc.signup_email = data.signup_email
|
||||
doc.username = data.username
|
||||
doc.full_name = data.full_name
|
||||
doc.invite_code = data.invite_code
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
user = doc.create_user(data.password)
|
||||
if user:
|
||||
doc.status = "Registered"
|
||||
doc.save(ignore_permissions=True)
|
||||
user = doc.create_user(data.password)
|
||||
if user:
|
||||
doc.status = "Registered"
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
return "OK"
|
||||
return "OK"
|
||||
|
||||
@@ -1,62 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
from lms.lms.doctype.invite_request.invite_request import create_invite_request, update_invite
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from lms.lms.doctype.invite_request.invite_request import (
|
||||
create_invite_request,
|
||||
update_invite,
|
||||
)
|
||||
|
||||
|
||||
class TestInviteRequest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
create_invite_request("test_invite@example.com")
|
||||
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
create_invite_request("test_invite@example.com")
|
||||
def test_create_invite_request(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
invite = frappe.db.get_value(
|
||||
"Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=["invite_email", "status", "signup_email"],
|
||||
as_dict=True,
|
||||
)
|
||||
self.assertEqual(invite.status, "Approved")
|
||||
self.assertEqual(invite.signup_email, None)
|
||||
|
||||
def test_create_invite_request(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
invite = frappe.db.get_value("Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=["invite_email", "status", "signup_email"],
|
||||
as_dict=True)
|
||||
self.assertEqual(invite.status, "Approved")
|
||||
self.assertEqual(invite.signup_email, None)
|
||||
def test_create_invite_request_update(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
|
||||
def test_create_invite_request_update(self):
|
||||
if frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"}):
|
||||
data = {
|
||||
"signup_email": "test_invite@example.com",
|
||||
"username": "test_invite",
|
||||
"full_name": "Test Invite",
|
||||
"password": "Test@invite",
|
||||
"invite_code": frappe.db.get_value(
|
||||
"Invite Request", {"invite_email": "test_invite@example.com"}, "name"
|
||||
),
|
||||
}
|
||||
|
||||
data = {
|
||||
"signup_email": "test_invite@example.com",
|
||||
"username": "test_invite",
|
||||
"full_name": "Test Invite",
|
||||
"password": "Test@invite",
|
||||
"invite_code": frappe.db.get_value("Invite Request", {"invite_email": "test_invite@example.com"}, "name")
|
||||
}
|
||||
update_invite(data)
|
||||
invite = frappe.db.get_value(
|
||||
"Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=[
|
||||
"invite_email",
|
||||
"status",
|
||||
"signup_email",
|
||||
"full_name",
|
||||
"username",
|
||||
"invite_code",
|
||||
"name",
|
||||
],
|
||||
as_dict=True,
|
||||
)
|
||||
self.assertEqual(invite.signup_email, "test_invite@example.com")
|
||||
self.assertEqual(invite.full_name, "Test Invite")
|
||||
self.assertEqual(invite.username, "test_invite")
|
||||
self.assertEqual(invite.invite_code, invite.name)
|
||||
self.assertEqual(invite.status, "Registered")
|
||||
|
||||
update_invite(data)
|
||||
invite = frappe.db.get_value("Invite Request",
|
||||
filters={"invite_email": "test_invite@example.com"},
|
||||
fieldname=["invite_email", "status", "signup_email", "full_name", "username", "invite_code", "name"],
|
||||
as_dict=True)
|
||||
self.assertEqual(invite.signup_email, "test_invite@example.com")
|
||||
self.assertEqual(invite.full_name, "Test Invite")
|
||||
self.assertEqual(invite.username, "test_invite")
|
||||
self.assertEqual(invite.invite_code, invite.name)
|
||||
self.assertEqual(invite.status, "Registered")
|
||||
user = frappe.db.get_value(
|
||||
"User",
|
||||
"test_invite@example.com",
|
||||
fieldname=["first_name", "username", "send_welcome_email", "user_type"],
|
||||
as_dict=True,
|
||||
)
|
||||
self.assertTrue(user)
|
||||
self.assertEqual(user.first_name, invite.full_name.split(" ")[0])
|
||||
self.assertEqual(user.username, invite.username)
|
||||
self.assertEqual(user.send_welcome_email, 0)
|
||||
self.assertEqual(user.user_type, "Website User")
|
||||
|
||||
user = frappe.db.get_value("User", "test_invite@example.com",
|
||||
fieldname=["first_name", "username", "send_welcome_email", "user_type"],
|
||||
as_dict=True)
|
||||
self.assertTrue(user)
|
||||
self.assertEqual(user.first_name, invite.full_name.split(" ")[0])
|
||||
self.assertEqual(user.username, invite.username)
|
||||
self.assertEqual(user.send_welcome_email, 0)
|
||||
self.assertEqual(user.user_type, "Website User")
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
if frappe.db.exists("User", "test_invite@example.com"):
|
||||
frappe.delete_doc("User", "test_invite@example.com")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
if frappe.db.exists("User", "test_invite@example.com"):
|
||||
frappe.delete_doc("User", "test_invite@example.com")
|
||||
|
||||
invite_request = frappe.db.exists("Invite Request", {"invite_email": "test_invite@example.com"})
|
||||
if invite_request:
|
||||
frappe.delete_doc("Invite Request", invite_request)
|
||||
invite_request = frappe.db.exists(
|
||||
"Invite Request", {"invite_email": "test_invite@example.com"}
|
||||
)
|
||||
if invite_request:
|
||||
frappe.delete_doc("Invite Request", invite_request)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Lesson Assignment', {
|
||||
frappe.ui.form.on("Lesson Assignment", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -2,48 +2,51 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LessonAssignment(Document):
|
||||
def validate(self):
|
||||
self.validate_duplicates()
|
||||
def validate(self):
|
||||
self.validate_duplicates()
|
||||
|
||||
|
||||
def validate_duplicates(self):
|
||||
if frappe.db.exists("Lesson Assignment", {"lesson": self.lesson, "member": self.member}):
|
||||
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))
|
||||
def validate_duplicates(self):
|
||||
if frappe.db.exists(
|
||||
"Lesson Assignment", {"lesson": self.lesson, "member": self.member}
|
||||
):
|
||||
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.whitelist()
|
||||
def upload_assignment(assignment, lesson):
|
||||
args = {
|
||||
"doctype": "Lesson Assignment",
|
||||
"lesson": lesson,
|
||||
"member": frappe.session.user
|
||||
}
|
||||
if frappe.db.exists(args):
|
||||
del args["doctype"]
|
||||
frappe.db.set_value("Lesson Assignment", args, "assignment", assignment)
|
||||
else:
|
||||
args.update({"assignment": assignment})
|
||||
lesson_work = frappe.get_doc(args)
|
||||
lesson_work.save(ignore_permissions=True)
|
||||
args = {
|
||||
"doctype": "Lesson Assignment",
|
||||
"lesson": lesson,
|
||||
"member": frappe.session.user,
|
||||
}
|
||||
if frappe.db.exists(args):
|
||||
del args["doctype"]
|
||||
frappe.db.set_value("Lesson Assignment", args, "assignment", assignment)
|
||||
else:
|
||||
args.update({"assignment": assignment})
|
||||
lesson_work = frappe.get_doc(args)
|
||||
lesson_work.save(ignore_permissions=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_assignment(lesson):
|
||||
assignment = frappe.db.get_value("Lesson Assignment", {
|
||||
"lesson": lesson,
|
||||
"member": frappe.session.user
|
||||
}, ["lesson", "member", "assignment"],
|
||||
as_dict=True)
|
||||
assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name")
|
||||
return assignment
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
assignment = frappe.db.get_value(
|
||||
"Lesson Assignment",
|
||||
{"lesson": lesson, "member": frappe.session.user},
|
||||
["lesson", "member", "assignment"],
|
||||
as_dict=True,
|
||||
)
|
||||
assignment.file_name = frappe.db.get_value(
|
||||
"File", {"file_url": assignment.assignment}, "file_name"
|
||||
)
|
||||
return assignment
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLessonAssignment(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LessonReference(Document):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Batch', {
|
||||
frappe.ui.form.on("LMS Batch", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -1,101 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from 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
|
||||
|
||||
|
||||
class LMSBatch(Document):
|
||||
def validate(self):
|
||||
pass
|
||||
#self.validate_if_mentor()
|
||||
def validate(self):
|
||||
pass
|
||||
# self.validate_if_mentor()
|
||||
|
||||
def validate_if_mentor(self):
|
||||
if not is_mentor(self.course, frappe.session.user):
|
||||
course_title = frappe.db.get_value("LMS Course", self.course, "title")
|
||||
frappe.throw(_("You are not a mentor of the course {0}").format(course_title))
|
||||
def validate_if_mentor(self):
|
||||
if not is_mentor(self.course, frappe.session.user):
|
||||
course_title = frappe.db.get_value("LMS Course", self.course, "title")
|
||||
frappe.throw(_("You are not a mentor of the course {0}").format(course_title))
|
||||
|
||||
def after_insert(self):
|
||||
create_membership(batch=self.name, course=self.course, member_type="Mentor")
|
||||
def after_insert(self):
|
||||
create_membership(batch=self.name, course=self.course, member_type="Mentor")
|
||||
|
||||
def is_member(self, email, member_type=None):
|
||||
"""Checks if a person is part of a batch.
|
||||
def is_member(self, email, member_type=None):
|
||||
"""Checks if a person is part of a batch.
|
||||
|
||||
If member_type is specified, checks if the person is a Student/Mentor.
|
||||
"""
|
||||
If member_type is specified, checks if the person is a Student/Mentor.
|
||||
"""
|
||||
|
||||
filters = {
|
||||
"batch": self.name,
|
||||
"member": email
|
||||
}
|
||||
if member_type:
|
||||
filters['member_type'] = member_type
|
||||
return frappe.db.exists("LMS Batch Membership", filters)
|
||||
filters = {"batch": self.name, "member": email}
|
||||
if member_type:
|
||||
filters["member_type"] = member_type
|
||||
return frappe.db.exists("LMS Batch Membership", filters)
|
||||
|
||||
def get_membership(self, email):
|
||||
"""Returns the membership document of given user."""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={"batch": self.name, "member": email},
|
||||
fieldname="name",
|
||||
)
|
||||
return frappe.get_doc("LMS Batch Membership", name)
|
||||
|
||||
def get_membership(self, email):
|
||||
"""Returns the membership document of given user.
|
||||
"""
|
||||
name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={
|
||||
"batch": self.name,
|
||||
"member": email
|
||||
},
|
||||
fieldname="name")
|
||||
return frappe.get_doc("LMS Batch Membership", name)
|
||||
def get_current_lesson(self, user):
|
||||
"""Returns the name of the current lesson for the given user."""
|
||||
membership = self.get_membership(user)
|
||||
return membership and membership.current_lesson
|
||||
|
||||
def get_current_lesson(self, user):
|
||||
"""Returns the name of the current lesson for the given user.
|
||||
"""
|
||||
membership = self.get_membership(user)
|
||||
return membership and membership.current_lesson
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_message(message, batch):
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Message",
|
||||
"batch": batch,
|
||||
"author": frappe.session.user,
|
||||
"message": message
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Message",
|
||||
"batch": batch,
|
||||
"author": frappe.session.user,
|
||||
"message": message,
|
||||
}
|
||||
)
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def switch_batch(course_name, email, batch_name):
|
||||
"""Switches the user from the current batch of the course to a new batch.
|
||||
"""
|
||||
membership = frappe.get_last_doc(
|
||||
"LMS Batch Membership",
|
||||
filters={"course": course_name, "member": email})
|
||||
"""Switches the user from the current batch of the course to a new batch."""
|
||||
membership = frappe.get_last_doc(
|
||||
"LMS Batch Membership", filters={"course": course_name, "member": email}
|
||||
)
|
||||
|
||||
batch = frappe.get_doc("LMS Batch", batch_name)
|
||||
if not batch:
|
||||
raise ValueError(f"Invalid Batch: {batch_name}")
|
||||
batch = frappe.get_doc("LMS Batch", batch_name)
|
||||
if not batch:
|
||||
raise ValueError(f"Invalid Batch: {batch_name}")
|
||||
|
||||
if batch.course != course_name:
|
||||
raise ValueError("Can not switch batches across courses")
|
||||
if batch.course != course_name:
|
||||
raise ValueError("Can not switch batches across courses")
|
||||
|
||||
if batch.is_member(email):
|
||||
print(f"{email} is already a member of {batch.title}")
|
||||
return
|
||||
if batch.is_member(email):
|
||||
print(f"{email} is already a member of {batch.title}")
|
||||
return
|
||||
|
||||
old_batch = frappe.get_doc("LMS Batch", membership.batch)
|
||||
old_batch = frappe.get_doc("LMS Batch", membership.batch)
|
||||
|
||||
print("updating membership", membership.name)
|
||||
membership.batch = batch_name
|
||||
membership.save()
|
||||
print("updating membership", membership.name)
|
||||
membership.batch = batch_name
|
||||
membership.save()
|
||||
|
||||
# update exercise submissions
|
||||
filters = {
|
||||
"owner": email,
|
||||
"batch": old_batch.name
|
||||
}
|
||||
for name in frappe.db.get_all("Exercise Submission", filters=filters, pluck='name'):
|
||||
doc = frappe.get_doc("Exercise Submission", name)
|
||||
print("updating exercise submission", name)
|
||||
doc.batch = batch_name
|
||||
doc.save()
|
||||
# update exercise submissions
|
||||
filters = {"owner": email, "batch": old_batch.name}
|
||||
for name in frappe.db.get_all("Exercise Submission", filters=filters, pluck="name"):
|
||||
doc = frappe.get_doc("Exercise Submission", name)
|
||||
print("updating exercise submission", name)
|
||||
doc.batch = batch_name
|
||||
doc.save()
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLMSBatch(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Batch Membership', {
|
||||
onload: function(frm) {
|
||||
frm.set_query('member', function(doc) {
|
||||
frappe.ui.form.on("LMS Batch Membership", {
|
||||
onload: function (frm) {
|
||||
frm.set_query("member", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,78 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LMSBatchMembership(Document):
|
||||
def validate(self):
|
||||
self.validate_membership_in_same_batch()
|
||||
self.validate_membership_in_different_batch_same_course()
|
||||
|
||||
def validate(self):
|
||||
self.validate_membership_in_same_batch()
|
||||
self.validate_membership_in_different_batch_same_course()
|
||||
def validate_membership_in_same_batch(self):
|
||||
filters = {"member": self.member, "course": self.course, "name": ["!=", self.name]}
|
||||
if self.batch:
|
||||
filters["batch"] = self.batch
|
||||
previous_membership = frappe.db.get_value(
|
||||
"LMS Batch Membership", filters, fieldname=["member_type", "member"], as_dict=1
|
||||
)
|
||||
|
||||
def validate_membership_in_same_batch(self):
|
||||
filters={
|
||||
"member": self.member,
|
||||
"course": self.course,
|
||||
"name": ["!=", self.name]
|
||||
}
|
||||
if self.batch:
|
||||
filters["batch"] = self.batch
|
||||
previous_membership = frappe.db.get_value("LMS Batch Membership",
|
||||
filters,
|
||||
fieldname=["member_type","member"],
|
||||
as_dict=1)
|
||||
if previous_membership:
|
||||
member_name = frappe.db.get_value("User", self.member, "full_name")
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
if previous_membership:
|
||||
member_name = frappe.db.get_value("User", self.member, "full_name")
|
||||
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))
|
||||
def validate_membership_in_different_batch_same_course(self):
|
||||
"""Ensures that a studnet is only part of one batch."""
|
||||
# nothing to worry if the member is not a student
|
||||
if self.member_type != "Student":
|
||||
return
|
||||
|
||||
def validate_membership_in_different_batch_same_course(self):
|
||||
"""Ensures that a studnet is only part of one batch.
|
||||
"""
|
||||
# nothing to worry if the member is not a student
|
||||
if self.member_type != "Student":
|
||||
return
|
||||
course = frappe.db.get_value("LMS Batch", self.batch, "course")
|
||||
memberships = frappe.get_all(
|
||||
"LMS Batch Membership",
|
||||
filters={
|
||||
"member": self.member,
|
||||
"name": ["!=", self.name],
|
||||
"member_type": "Student",
|
||||
"course": self.course,
|
||||
},
|
||||
fields=["batch", "member_type", "name"],
|
||||
)
|
||||
|
||||
course = frappe.db.get_value("LMS Batch", self.batch, "course")
|
||||
memberships = frappe.get_all(
|
||||
"LMS Batch Membership",
|
||||
filters={
|
||||
"member": self.member,
|
||||
"name": ["!=", self.name],
|
||||
"member_type": "Student",
|
||||
"course": self.course
|
||||
},
|
||||
fields=["batch", "member_type", "name"]
|
||||
)
|
||||
if memberships:
|
||||
membership = memberships[0]
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
if memberships:
|
||||
membership = memberships[0]
|
||||
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.whitelist()
|
||||
def create_membership(course, batch=None, member=None, member_type="Student", role="Member"):
|
||||
frappe.get_doc({
|
||||
"doctype": "LMS Batch Membership",
|
||||
"batch": batch,
|
||||
"course": course,
|
||||
"role": role,
|
||||
"member_type": member_type,
|
||||
"member": member or frappe.session.user
|
||||
}).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
def create_membership(
|
||||
course, batch=None, member=None, member_type="Student", role="Member"
|
||||
):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Batch Membership",
|
||||
"batch": batch,
|
||||
"course": course,
|
||||
"role": role,
|
||||
"member_type": member_type,
|
||||
"member": member or frappe.session.user,
|
||||
}
|
||||
).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_current_membership(batch, course, member):
|
||||
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": course})
|
||||
for membership in all_memberships:
|
||||
frappe.db.set_value("LMS Batch Membership", membership.name, "is_current", 0)
|
||||
all_memberships = frappe.get_all(
|
||||
"LMS Batch Membership", {"member": member, "course": course}
|
||||
)
|
||||
for membership in all_memberships:
|
||||
frappe.db.set_value("LMS Batch Membership", membership.name, "is_current", 0)
|
||||
|
||||
current_membership = frappe.get_all("LMS Batch Membership", {"batch": batch, "member": member})
|
||||
if len(current_membership):
|
||||
frappe.db.set_value("LMS Batch Membership", current_membership[0].name, "is_current", 1)
|
||||
current_membership = frappe.get_all(
|
||||
"LMS Batch Membership", {"batch": batch, "member": member}
|
||||
)
|
||||
if len(current_membership):
|
||||
frappe.db.set_value(
|
||||
"LMS Batch Membership", current_membership[0].name, "is_current", 1
|
||||
)
|
||||
|
||||
@@ -1,62 +1,67 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
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):
|
||||
def setUp(self):
|
||||
frappe.db.sql("DELETE FROM `tabLMS Batch Membership`")
|
||||
frappe.db.sql("DELETE FROM `tabLMS Batch`")
|
||||
frappe.db.sql('delete from `tabLMS Course Mentor Mapping`')
|
||||
frappe.db.sql("DELETE FROM `tabUser` where email like '%@test.com'")
|
||||
def setUp(self):
|
||||
frappe.db.sql("DELETE FROM `tabLMS Batch Membership`")
|
||||
frappe.db.sql("DELETE FROM `tabLMS Batch`")
|
||||
frappe.db.sql("delete from `tabLMS Course Mentor Mapping`")
|
||||
frappe.db.sql("DELETE FROM `tabUser` where email like '%@test.com'")
|
||||
|
||||
def new_course_batch(self):
|
||||
course = new_course("Test Course")
|
||||
def new_course_batch(self):
|
||||
course = new_course("Test Course")
|
||||
|
||||
new_user("Test Mentor", "mentor@test.com")
|
||||
# without this, the creating batch will fail
|
||||
course.add_mentor("mentor@test.com")
|
||||
new_user("Test Mentor", "mentor@test.com")
|
||||
# without this, the creating batch will fail
|
||||
course.add_mentor("mentor@test.com")
|
||||
|
||||
frappe.session.user = "mentor@test.com"
|
||||
frappe.session.user = "mentor@test.com"
|
||||
|
||||
batch = frappe.get_doc({
|
||||
"doctype": "LMS Batch",
|
||||
"name": "test-batch",
|
||||
"title": "Test Batch",
|
||||
"course": course.name
|
||||
})
|
||||
batch.insert(ignore_permissions=True)
|
||||
batch = frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Batch",
|
||||
"name": "test-batch",
|
||||
"title": "Test Batch",
|
||||
"course": course.name,
|
||||
}
|
||||
)
|
||||
batch.insert(ignore_permissions=True)
|
||||
|
||||
frappe.session.user = "Administrator"
|
||||
return course, batch
|
||||
frappe.session.user = "Administrator"
|
||||
return course, batch
|
||||
|
||||
def add_membership(self, batch_name, member_name, member_type="Student"):
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Batch Membership",
|
||||
"batch": batch_name,
|
||||
"member": member_name,
|
||||
"member_type": member_type
|
||||
})
|
||||
doc.insert()
|
||||
return doc
|
||||
def add_membership(self, batch_name, member_name, member_type="Student"):
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Batch Membership",
|
||||
"batch": batch_name,
|
||||
"member": member_name,
|
||||
"member_type": member_type,
|
||||
}
|
||||
)
|
||||
doc.insert()
|
||||
return doc
|
||||
|
||||
def test_membership(self):
|
||||
course, batch = self.new_course_batch()
|
||||
member = new_user("Test", "test01@test.com")
|
||||
membership = self.add_membership(batch.name, member.name)
|
||||
def test_membership(self):
|
||||
course, batch = self.new_course_batch()
|
||||
member = new_user("Test", "test01@test.com")
|
||||
membership = self.add_membership(batch.name, member.name)
|
||||
|
||||
assert membership.course == course.name
|
||||
assert membership.member_name == member.full_name
|
||||
assert membership.course == course.name
|
||||
assert membership.member_name == member.full_name
|
||||
|
||||
def test_membership_change_role(self):
|
||||
course, batch = self.new_course_batch()
|
||||
member = new_user("Test", "test01@test.com")
|
||||
membership = self.add_membership(batch.name, member.name)
|
||||
def test_membership_change_role(self):
|
||||
course, batch = self.new_course_batch()
|
||||
member = new_user("Test", "test01@test.com")
|
||||
membership = self.add_membership(batch.name, member.name)
|
||||
|
||||
# it should be possible to change role
|
||||
membership.role = "Admin"
|
||||
membership.save()
|
||||
# it should be possible to change role
|
||||
membership.role = "Admin"
|
||||
membership.save()
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Certificate', {
|
||||
onload: (frm) => {
|
||||
frm.set_query("member", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
refresh: (frm) => {
|
||||
if (frm.doc.name) frm.add_web_link(`/courses/${frm.doc.course}/${frm.doc.name}`, 'See on Website')
|
||||
}
|
||||
frappe.ui.form.on("LMS Certificate", {
|
||||
onload: (frm) => {
|
||||
frm.set_query("member", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
refresh: (frm) => {
|
||||
if (frm.doc.name)
|
||||
frm.add_web_link(
|
||||
`/courses/${frm.doc.course}/${frm.doc.name}`,
|
||||
"See on Website"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,49 +2,55 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import nowdate, add_years
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import add_years, nowdate
|
||||
from frappe.utils.pdf import get_pdf
|
||||
|
||||
from lms.lms.utils import is_certified
|
||||
|
||||
class LMSCertificate(Document):
|
||||
|
||||
def before_insert(self):
|
||||
certificates = frappe.get_all("LMS Certificate", {
|
||||
"member": self.member,
|
||||
"course": self.course
|
||||
})
|
||||
if len(certificates):
|
||||
full_name = frappe.db.get_value("User", self.member, "full_name")
|
||||
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))
|
||||
class LMSCertificate(Document):
|
||||
def before_insert(self):
|
||||
certificates = frappe.get_all(
|
||||
"LMS Certificate", {"member": self.member, "course": self.course}
|
||||
)
|
||||
if len(certificates):
|
||||
full_name = frappe.db.get_value("User", self.member, "full_name")
|
||||
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.whitelist()
|
||||
def create_certificate(course):
|
||||
certificate = is_certified(course)
|
||||
certificate = is_certified(course)
|
||||
|
||||
if certificate:
|
||||
return certificate
|
||||
if certificate:
|
||||
return certificate
|
||||
|
||||
else:
|
||||
expires_after_yrs = int(frappe.db.get_value("LMS Course", course, "expiry"))
|
||||
expiry_date = None
|
||||
if expires_after_yrs:
|
||||
expiry_date = add_years(nowdate(), expires_after_yrs)
|
||||
else:
|
||||
expires_after_yrs = int(frappe.db.get_value("LMS Course", course, "expiry"))
|
||||
expiry_date = None
|
||||
if expires_after_yrs:
|
||||
expiry_date = add_years(nowdate(), expires_after_yrs)
|
||||
|
||||
certificate = frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Certificate",
|
||||
"member": frappe.session.user,
|
||||
"course": course,
|
||||
"issue_date": nowdate(),
|
||||
"expiry_date": expiry_date,
|
||||
}
|
||||
)
|
||||
certificate.save(ignore_permissions=True)
|
||||
return certificate
|
||||
|
||||
certificate = frappe.get_doc({
|
||||
"doctype": "LMS Certificate",
|
||||
"member": frappe.session.user,
|
||||
"course": course,
|
||||
"issue_date": nowdate(),
|
||||
"expiry_date": expiry_date
|
||||
})
|
||||
certificate.save(ignore_permissions=True)
|
||||
return certificate
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_certificate_pdf(html):
|
||||
frappe.local.response.filename = "certificate.pdf"
|
||||
frappe.local.response.filecontent = get_pdf(html, {"orientation": "LandScape"})
|
||||
frappe.local.response.type = "pdf"
|
||||
frappe.local.response.filename = "certificate.pdf"
|
||||
frappe.local.response.filecontent = get_pdf(html, {"orientation": "LandScape"})
|
||||
frappe.local.response.type = "pdf"
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
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 frappe.utils import nowdate, add_years, cint
|
||||
from lms.lms.doctype.lms_course.test_lms_course import new_course
|
||||
|
||||
|
||||
class TestLMSCertificate(unittest.TestCase):
|
||||
def test_certificate_creation(self):
|
||||
course = new_course("Test Certificate", {"enable_certification": 1, "expiry": 2})
|
||||
certificate = create_certificate(course.name)
|
||||
|
||||
def test_certificate_creation(self):
|
||||
course = new_course("Test Certificate", {
|
||||
"enable_certification": 1,
|
||||
"expiry": 2
|
||||
})
|
||||
certificate = create_certificate(course.name)
|
||||
self.assertEqual(certificate.member, "Administrator")
|
||||
self.assertEqual(certificate.course, course.name)
|
||||
self.assertEqual(certificate.issue_date, nowdate())
|
||||
self.assertEqual(certificate.expiry_date, add_years(nowdate(), cint(course.expiry)))
|
||||
|
||||
self.assertEqual(certificate.member, "Administrator")
|
||||
self.assertEqual(certificate.course, course.name)
|
||||
self.assertEqual(certificate.issue_date, nowdate())
|
||||
self.assertEqual(certificate.expiry_date, add_years(nowdate(), cint(course.expiry)))
|
||||
|
||||
frappe.db.delete("LMS Certificate", certificate.name)
|
||||
frappe.db.delete("LMS Course", course.name)
|
||||
frappe.db.delete("LMS Certificate", certificate.name)
|
||||
frappe.db.delete("LMS Course", course.name)
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
// Copyright (c) 2022, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Certificate Evaluation', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.status == "Pass") {
|
||||
frm.add_custom_button(__("Create LMS Certificate"), () => {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate",
|
||||
frm: frm
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
frappe.ui.form.on("LMS Certificate Evaluation", {
|
||||
refresh: function (frm) {
|
||||
if (frm.doc.status == "Pass") {
|
||||
frm.add_custom_button(__("Create LMS Certificate"), () => {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate",
|
||||
frm: frm,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
frm.set_query("course", function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"enable_certification": true,
|
||||
"grant_certificate_after": "Evaluation"
|
||||
}
|
||||
};
|
||||
});
|
||||
onload: function (frm) {
|
||||
frm.set_query("course", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
enable_certification: true,
|
||||
grant_certificate_after: "Evaluation",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('member', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
frm.set_query("member", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,14 +5,17 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
|
||||
class LMSCertificateEvaluation(Document):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_lms_certificate(source_name, target_doc=None):
|
||||
doc = get_mapped_doc("LMS Certificate Evaluation", source_name, {
|
||||
"LMS Certificate Evaluation": {
|
||||
"doctype": "LMS Certificate"
|
||||
}
|
||||
}, target_doc)
|
||||
return doc
|
||||
doc = get_mapped_doc(
|
||||
"LMS Certificate Evaluation",
|
||||
source_name,
|
||||
{"LMS Certificate Evaluation": {"doctype": "LMS Certificate"}},
|
||||
target_doc,
|
||||
)
|
||||
return doc
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
// Copyright (c) 2022, Frappe and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Certificate Request', {
|
||||
refresh: function(frm) {
|
||||
frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation",
|
||||
frm: frm
|
||||
});
|
||||
});
|
||||
},
|
||||
frappe.ui.form.on("LMS Certificate Request", {
|
||||
refresh: function (frm) {
|
||||
frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation",
|
||||
frm: frm,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
frm.set_query('member', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
onload: function (frm) {
|
||||
frm.set_query("member", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,54 +2,63 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe import _
|
||||
from frappe.utils import getdate, format_date, format_time
|
||||
from frappe.utils import format_date, format_time, getdate
|
||||
|
||||
|
||||
class LMSCertificateRequest(Document):
|
||||
def validate(self):
|
||||
self.validate_if_existing_requests()
|
||||
|
||||
def validate(self):
|
||||
self.validate_if_existing_requests()
|
||||
def validate_if_existing_requests(self):
|
||||
existing_requests = frappe.get_all(
|
||||
"LMS Certificate Request",
|
||||
{"member": self.member, "course": self.course},
|
||||
["date", "start_time", "course"],
|
||||
)
|
||||
|
||||
def validate_if_existing_requests(self):
|
||||
existing_requests = frappe.get_all("LMS Certificate Request", {
|
||||
"member": self.member,
|
||||
"course": self.course
|
||||
}, ["date", "start_time", "course"])
|
||||
for req in existing_requests:
|
||||
if req.date == getdate(self.date) and getdate() <= getdate(self.date):
|
||||
course_title = frappe.db.get_value("LMS Course", req.course, "title")
|
||||
frappe.throw(
|
||||
_("You already have an evaluation on {0} at {1} for the course {2}.").format(
|
||||
format_date(req.date, "medium"),
|
||||
format_time(req.start_time, "short"),
|
||||
course_title,
|
||||
)
|
||||
)
|
||||
|
||||
for req in existing_requests:
|
||||
if req.date == getdate(self.date) and getdate() <= getdate(self.date):
|
||||
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.whitelist()
|
||||
def create_certificate_request(course, date, day, start_time, end_time):
|
||||
is_member = frappe.db.exists({
|
||||
"doctype": "LMS Batch Membership",
|
||||
"course": course,
|
||||
"member": frappe.session.user
|
||||
})
|
||||
is_member = frappe.db.exists(
|
||||
{"doctype": "LMS Batch Membership", "course": course, "member": frappe.session.user}
|
||||
)
|
||||
|
||||
if not is_member:
|
||||
return
|
||||
if not is_member:
|
||||
return
|
||||
|
||||
frappe.get_doc({
|
||||
"doctype": "LMS Certificate Request",
|
||||
"course": course,
|
||||
"member": frappe.session.user,
|
||||
"date": date,
|
||||
"day": day,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time
|
||||
}).save(ignore_permissions=True)
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "LMS Certificate Request",
|
||||
"course": course,
|
||||
"member": frappe.session.user,
|
||||
"date": date,
|
||||
"day": day,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time,
|
||||
}
|
||||
).save(ignore_permissions=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_lms_certificate_evaluation(source_name, target_doc=None):
|
||||
doc = get_mapped_doc("LMS Certificate Request", source_name, {
|
||||
"LMS Certificate Request": {
|
||||
"doctype": "LMS Certificate Evaluation"
|
||||
}
|
||||
}, target_doc)
|
||||
return doc
|
||||
doc = get_mapped_doc(
|
||||
"LMS Certificate Request",
|
||||
source_name,
|
||||
{"LMS Certificate Request": {"doctype": "LMS Certificate Evaluation"}},
|
||||
target_doc,
|
||||
)
|
||||
return doc
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Course', {
|
||||
frappe.ui.form.on("LMS Course", {
|
||||
onload: function (frm) {
|
||||
frm.set_query("chapter", "chapters", function () {
|
||||
return {
|
||||
filters: {
|
||||
course: frm.doc.name,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
onload: function (frm) {
|
||||
frm.set_query("instructor", "instructors", function () {
|
||||
return {
|
||||
filters: {
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("chapter", "chapters", function () {
|
||||
return {
|
||||
filters: {
|
||||
"course": frm.doc.name,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("instructor", "instructors", function () {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("course", "related_courses", function () {
|
||||
return {
|
||||
filters: {
|
||||
"published": true,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
frm.set_query("course", "related_courses", function () {
|
||||
return {
|
||||
filters: {
|
||||
published: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,307 +1,313 @@
|
||||
# Copyright (c) 2021, Frappe and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
import json
|
||||
from ...utils import generate_slug, validate_image
|
||||
from frappe.utils import cint
|
||||
|
||||
from lms.lms.utils import get_chapters
|
||||
|
||||
from ...utils import generate_slug, validate_image
|
||||
|
||||
|
||||
class LMSCourse(Document):
|
||||
def validate(self):
|
||||
self.validate_instructors()
|
||||
self.validate_status()
|
||||
self.image = validate_image(self.image)
|
||||
|
||||
def validate_instructors(self):
|
||||
if self.is_new() and not self.instructors:
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Course Instructor",
|
||||
"instructor": self.owner,
|
||||
"parent": self.name,
|
||||
"parentfield": "instructors",
|
||||
"parenttype": "LMS Course",
|
||||
}
|
||||
).save(ignore_permissions=True)
|
||||
|
||||
def validate(self):
|
||||
self.validate_instructors()
|
||||
self.validate_status()
|
||||
self.image = validate_image(self.image)
|
||||
def validate_status(self):
|
||||
if self.published:
|
||||
self.status = "Approved"
|
||||
|
||||
def on_update(self):
|
||||
if not self.upcoming and self.has_value_changed("upcoming"):
|
||||
self.send_email_to_interested_users()
|
||||
|
||||
def validate_instructors(self):
|
||||
if self.is_new() and not self.instructors:
|
||||
frappe.get_doc({
|
||||
"doctype": "Course Instructor",
|
||||
"instructor": self.owner,
|
||||
"parent": self.name,
|
||||
"parentfield": "instructors",
|
||||
"parenttype": "LMS Course"
|
||||
}).save(ignore_permissions=True)
|
||||
def send_email_to_interested_users(self):
|
||||
interested_users = frappe.get_all(
|
||||
"LMS Course Interest", {"course": self.name}, ["name", "user"]
|
||||
)
|
||||
subject = self.title + " is available!"
|
||||
args = {
|
||||
"title": self.title,
|
||||
"course_link": f"/courses/{self.name}",
|
||||
"app_name": frappe.db.get_single_value("System Settings", "app_name"),
|
||||
"site_url": frappe.utils.get_url(),
|
||||
}
|
||||
|
||||
for user in interested_users:
|
||||
args["first_name"] = frappe.db.get_value("User", user.user, "first_name")
|
||||
email_args = frappe._dict(
|
||||
recipients=user.user,
|
||||
subject=subject,
|
||||
header=[subject, "green"],
|
||||
template="lms_course_interest",
|
||||
args=args,
|
||||
now=True,
|
||||
)
|
||||
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)
|
||||
|
||||
def validate_status(self):
|
||||
if self.published:
|
||||
self.status = "Approved"
|
||||
def autoname(self):
|
||||
if not self.name:
|
||||
self.name = generate_slug(self.title, "LMS Course")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Course#{self.name}>"
|
||||
|
||||
def on_update(self):
|
||||
if not self.upcoming and self.has_value_changed("upcoming"):
|
||||
self.send_email_to_interested_users()
|
||||
def has_mentor(self, email):
|
||||
"""Checks if this course has a mentor with given email."""
|
||||
if not email or email == "Guest":
|
||||
return False
|
||||
|
||||
mapping = frappe.get_all(
|
||||
"LMS Course Mentor Mapping", {"course": self.name, "mentor": email}
|
||||
)
|
||||
return mapping != []
|
||||
|
||||
def send_email_to_interested_users(self):
|
||||
interested_users = frappe.get_all("LMS Course Interest", {
|
||||
"course": self.name
|
||||
},
|
||||
["name", "user"])
|
||||
subject = self.title + " is available!"
|
||||
args = {
|
||||
"title": self.title,
|
||||
"course_link": "/courses/{0}".format(self.name),
|
||||
"app_name": frappe.db.get_single_value("System Settings", "app_name"),
|
||||
"site_url": frappe.utils.get_url()
|
||||
}
|
||||
def add_mentor(self, email):
|
||||
"""Adds a new mentor to the course."""
|
||||
if not email:
|
||||
raise ValueError("Invalid email")
|
||||
if email == "Guest":
|
||||
raise ValueError("Guest user can not be added as a mentor")
|
||||
|
||||
for user in interested_users:
|
||||
args["first_name"] = frappe.db.get_value("User", user.user, "first_name")
|
||||
email_args = frappe._dict(
|
||||
recipients = user.user,
|
||||
subject = subject,
|
||||
header = [subject, "green"],
|
||||
template = "lms_course_interest",
|
||||
args = args,
|
||||
now = True)
|
||||
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)
|
||||
# given user is already a mentor
|
||||
if self.has_mentor(email):
|
||||
return
|
||||
|
||||
doc = frappe.get_doc(
|
||||
{"doctype": "LMS Course Mentor Mapping", "course": self.name, "mentor": email}
|
||||
)
|
||||
doc.insert()
|
||||
|
||||
def autoname(self):
|
||||
if not self.name:
|
||||
self.name = generate_slug(self.title, "LMS Course")
|
||||
def get_student_batch(self, email):
|
||||
"""Returns the batch the given student is part of.
|
||||
|
||||
Returns None if the student is not part of any batch.
|
||||
"""
|
||||
if not email:
|
||||
return
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Course#{self.name}>"
|
||||
batch_name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={"course": self.name, "member_type": "Student", "member": email},
|
||||
fieldname="batch",
|
||||
)
|
||||
return batch_name and frappe.get_doc("LMS Batch", batch_name)
|
||||
|
||||
def get_batches(self, mentor=None):
|
||||
batches = frappe.get_all("LMS Batch", {"course": self.name})
|
||||
if mentor:
|
||||
# TODO: optimize this
|
||||
memberships = frappe.db.get_all(
|
||||
"LMS Batch Membership", {"member": mentor}, ["batch"]
|
||||
)
|
||||
batch_names = {m.batch for m in memberships}
|
||||
return [b for b in batches if b.name in batch_names]
|
||||
|
||||
def has_mentor(self, email):
|
||||
"""Checks if this course has a mentor with given email.
|
||||
"""
|
||||
if not email or email == "Guest":
|
||||
return False
|
||||
def get_cohorts(self):
|
||||
return frappe.get_all(
|
||||
"Cohort",
|
||||
{"course": self.name},
|
||||
["name", "slug", "title", "begin_date", "end_date"],
|
||||
order_by="creation",
|
||||
)
|
||||
|
||||
mapping = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name, "mentor": email})
|
||||
return mapping != []
|
||||
def get_cohort(self, cohort_slug):
|
||||
name = frappe.get_value("Cohort", {"course": self.name, "slug": cohort_slug})
|
||||
return name and frappe.get_doc("Cohort", name)
|
||||
|
||||
def reindex_exercises(self):
|
||||
for i, c in enumerate(get_chapters(self.name), start=1):
|
||||
self._reindex_exercises_in_chapter(c, i)
|
||||
|
||||
def add_mentor(self, email):
|
||||
"""Adds a new mentor to the course.
|
||||
"""
|
||||
if not email:
|
||||
raise ValueError("Invalid email")
|
||||
if email == "Guest":
|
||||
raise ValueError("Guest user can not be added as a mentor")
|
||||
def _reindex_exercises_in_chapter(self, c, index):
|
||||
i = 1
|
||||
for lesson in self.get_lessons(c):
|
||||
for exercise in lesson.get_exercises():
|
||||
exercise.index_ = i
|
||||
exercise.index_label = f"{index}.{i}"
|
||||
exercise.save()
|
||||
i += 1
|
||||
|
||||
# given user is already a mentor
|
||||
if self.has_mentor(email):
|
||||
return
|
||||
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Course Mentor Mapping",
|
||||
"course": self.name,
|
||||
"mentor": email
|
||||
})
|
||||
doc.insert()
|
||||
|
||||
|
||||
def get_student_batch(self, email):
|
||||
"""Returns the batch the given student is part of.
|
||||
|
||||
Returns None if the student is not part of any batch.
|
||||
"""
|
||||
if not email:
|
||||
return
|
||||
|
||||
batch_name = frappe.get_value(
|
||||
doctype="LMS Batch Membership",
|
||||
filters={
|
||||
"course": self.name,
|
||||
"member_type": "Student",
|
||||
"member": email
|
||||
},
|
||||
fieldname="batch")
|
||||
return batch_name and frappe.get_doc("LMS Batch", batch_name)
|
||||
|
||||
|
||||
def get_batches(self, mentor=None):
|
||||
batches = frappe.get_all("LMS Batch", {"course": self.name})
|
||||
if mentor:
|
||||
# TODO: optimize this
|
||||
memberships = frappe.db.get_all(
|
||||
"LMS Batch Membership",
|
||||
{"member": mentor},
|
||||
["batch"])
|
||||
batch_names = {m.batch for m in memberships}
|
||||
return [b for b in batches if b.name in batch_names]
|
||||
|
||||
|
||||
def get_cohorts(self):
|
||||
return frappe.get_all("Cohort",
|
||||
{"course": self.name},
|
||||
["name", "slug", "title", "begin_date", "end_date"],
|
||||
order_by="creation")
|
||||
|
||||
|
||||
def get_cohort(self, cohort_slug):
|
||||
name = frappe.get_value("Cohort", {"course": self.name, "slug": cohort_slug})
|
||||
return name and frappe.get_doc("Cohort", name)
|
||||
|
||||
|
||||
def reindex_exercises(self):
|
||||
for i, c in enumerate(get_chapters(self.name), start=1):
|
||||
self._reindex_exercises_in_chapter(c, i)
|
||||
|
||||
|
||||
def _reindex_exercises_in_chapter(self, c, index):
|
||||
i = 1
|
||||
for lesson in self.get_lessons(c):
|
||||
for exercise in lesson.get_exercises():
|
||||
exercise.index_ = i
|
||||
exercise.index_label = f"{index}.{i}"
|
||||
exercise.save()
|
||||
i += 1
|
||||
|
||||
|
||||
def get_all_memberships(self, member):
|
||||
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": self.name}, ["batch"])
|
||||
for membership in all_memberships:
|
||||
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
||||
return all_memberships
|
||||
def get_all_memberships(self, member):
|
||||
all_memberships = frappe.get_all(
|
||||
"LMS Batch Membership", {"member": member, "course": self.name}, ["batch"]
|
||||
)
|
||||
for membership in all_memberships:
|
||||
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
||||
return all_memberships
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def reindex_exercises(doc):
|
||||
course_data = json.loads(doc)
|
||||
course = frappe.get_doc("LMS Course", course_data['name'])
|
||||
course.reindex_exercises()
|
||||
frappe.msgprint("All exercises in this course have been re-indexed.")
|
||||
course_data = json.loads(doc)
|
||||
course = frappe.get_doc("LMS Course", course_data["name"])
|
||||
course.reindex_exercises()
|
||||
frappe.msgprint("All exercises in this course have been re-indexed.")
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def search_course(text):
|
||||
search_courses = []
|
||||
courses = frappe.get_all("LMS Course",
|
||||
filters= {
|
||||
"published": True
|
||||
},
|
||||
or_filters = {
|
||||
"title": ["like", "%{0}%".format(text)],
|
||||
"tags": ["like", "%{0}%".format(text)],
|
||||
"short_introduction": ["like", "%{0}%".format(text)],
|
||||
"description": ["like", "%{0}%".format(text)],
|
||||
})
|
||||
search_courses = []
|
||||
courses = frappe.get_all(
|
||||
"LMS Course",
|
||||
filters={"published": True},
|
||||
or_filters={
|
||||
"title": ["like", f"%{text}%"],
|
||||
"tags": ["like", f"%{text}%"],
|
||||
"short_introduction": ["like", f"%{text}%"],
|
||||
"description": ["like", f"%{text}%"],
|
||||
},
|
||||
)
|
||||
|
||||
""" for course in courses:
|
||||
""" for course in courses:
|
||||
search_courses.append(frappe.get_doc("LMS Course", course)) """
|
||||
|
||||
""" template = frappe.render_template("lms/templates/course_list.html", {
|
||||
""" template = frappe.render_template("lms/templates/course_list.html", {
|
||||
"title": _("Search Results"),
|
||||
"courses": search_courses,
|
||||
"widgets": Widgets()
|
||||
}) """
|
||||
|
||||
return courses
|
||||
return courses
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def submit_for_review(course):
|
||||
chapters = frappe.get_all("Chapter Reference", {"parent": course})
|
||||
if not len(chapters):
|
||||
return "No Chp"
|
||||
frappe.db.set_value("LMS Course", course, "status", "Under Review")
|
||||
return "OK"
|
||||
chapters = frappe.get_all("Chapter Reference", {"parent": course})
|
||||
if not len(chapters):
|
||||
return "No Chp"
|
||||
frappe.db.set_value("LMS Course", course, "status", "Under Review")
|
||||
return "OK"
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_course(tags, title, short_introduction, video_link, description, course, published, upcoming, image=None):
|
||||
if course:
|
||||
doc = frappe.get_doc("LMS Course", course)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Course"
|
||||
})
|
||||
def save_course(
|
||||
tags,
|
||||
title,
|
||||
short_introduction,
|
||||
video_link,
|
||||
description,
|
||||
course,
|
||||
published,
|
||||
upcoming,
|
||||
image=None,
|
||||
):
|
||||
if course:
|
||||
doc = frappe.get_doc("LMS Course", course)
|
||||
else:
|
||||
doc = frappe.get_doc({"doctype": "LMS Course"})
|
||||
|
||||
doc.update({
|
||||
"title": title,
|
||||
"short_introduction": short_introduction,
|
||||
"video_link": video_link,
|
||||
"image": image,
|
||||
"description": description,
|
||||
"tags": tags,
|
||||
"published": cint(published),
|
||||
"upcoming": cint(upcoming)
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
return doc.name
|
||||
doc.update(
|
||||
{
|
||||
"title": title,
|
||||
"short_introduction": short_introduction,
|
||||
"video_link": video_link,
|
||||
"image": image,
|
||||
"description": description,
|
||||
"tags": tags,
|
||||
"published": cint(published),
|
||||
"upcoming": cint(upcoming),
|
||||
}
|
||||
)
|
||||
doc.save(ignore_permissions=True)
|
||||
return doc.name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_chapter(course, title, chapter_description, idx, chapter):
|
||||
if chapter:
|
||||
doc = frappe.get_doc("Course Chapter", chapter)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Course Chapter"
|
||||
})
|
||||
if chapter:
|
||||
doc = frappe.get_doc("Course Chapter", chapter)
|
||||
else:
|
||||
doc = frappe.get_doc({"doctype": "Course Chapter"})
|
||||
|
||||
doc.update({
|
||||
"course": course,
|
||||
"title": title,
|
||||
"description": chapter_description
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
doc.update({"course": course, "title": title, "description": chapter_description})
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
if chapter:
|
||||
chapter_reference = frappe.get_doc("Chapter Reference", {"chapter": chapter})
|
||||
else:
|
||||
chapter_reference = frappe.get_doc({
|
||||
"doctype": "Chapter Reference",
|
||||
"parent": course,
|
||||
"parenttype": "LMS Course",
|
||||
"parentfield": "chapters",
|
||||
"idx": idx
|
||||
})
|
||||
if chapter:
|
||||
chapter_reference = frappe.get_doc("Chapter Reference", {"chapter": chapter})
|
||||
else:
|
||||
chapter_reference = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Chapter Reference",
|
||||
"parent": course,
|
||||
"parenttype": "LMS Course",
|
||||
"parentfield": "chapters",
|
||||
"idx": idx,
|
||||
}
|
||||
)
|
||||
|
||||
chapter_reference.update({"chapter": doc.name})
|
||||
chapter_reference.save(ignore_permissions=True)
|
||||
chapter_reference.update({"chapter": doc.name})
|
||||
chapter_reference.save(ignore_permissions=True)
|
||||
|
||||
return doc.name
|
||||
return doc.name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None, question=None, file_type=None):
|
||||
if lesson:
|
||||
doc = frappe.get_doc("Course Lesson", lesson)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Course Lesson"
|
||||
})
|
||||
def save_lesson(
|
||||
title,
|
||||
body,
|
||||
chapter,
|
||||
preview,
|
||||
idx,
|
||||
lesson,
|
||||
youtube=None,
|
||||
quiz_id=None,
|
||||
question=None,
|
||||
file_type=None,
|
||||
):
|
||||
if lesson:
|
||||
doc = frappe.get_doc("Course Lesson", lesson)
|
||||
else:
|
||||
doc = frappe.get_doc({"doctype": "Course Lesson"})
|
||||
|
||||
doc.update({
|
||||
"chapter": chapter,
|
||||
"title": title,
|
||||
"body": body,
|
||||
"include_in_preview": preview,
|
||||
"youtube": youtube,
|
||||
"quiz_id": quiz_id,
|
||||
"question": question,
|
||||
"file_type": file_type
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
doc.update(
|
||||
{
|
||||
"chapter": chapter,
|
||||
"title": title,
|
||||
"body": body,
|
||||
"include_in_preview": preview,
|
||||
"youtube": youtube,
|
||||
"quiz_id": quiz_id,
|
||||
"question": question,
|
||||
"file_type": file_type,
|
||||
}
|
||||
)
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
if lesson:
|
||||
lesson_reference = frappe.get_doc("Lesson Reference", {"lesson": lesson})
|
||||
else:
|
||||
lesson_reference = frappe.get_doc({
|
||||
"doctype": "Lesson Reference",
|
||||
"parent": chapter,
|
||||
"parenttype": "Course Chapter",
|
||||
"parentfield": "lessons",
|
||||
"idx": idx
|
||||
})
|
||||
if lesson:
|
||||
lesson_reference = frappe.get_doc("Lesson Reference", {"lesson": lesson})
|
||||
else:
|
||||
lesson_reference = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Lesson Reference",
|
||||
"parent": chapter,
|
||||
"parenttype": "Course Chapter",
|
||||
"parentfield": "lessons",
|
||||
"idx": idx,
|
||||
}
|
||||
)
|
||||
|
||||
lesson_reference.update({"lesson": doc.name})
|
||||
lesson_reference.save(ignore_permissions=True)
|
||||
lesson_reference.update({"lesson": doc.name})
|
||||
lesson_reference.save(ignore_permissions=True)
|
||||
|
||||
return doc.name
|
||||
return doc.name
|
||||
|
||||
@@ -1,93 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
|
||||
from .lms_course import LMSCourse
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLMSCourse(unittest.TestCase):
|
||||
def test_new_course(self):
|
||||
course = new_course("Test Course")
|
||||
assert course.title == "Test Course"
|
||||
assert course.name == "test-course"
|
||||
|
||||
# disabled this test as it is failing
|
||||
def _test_add_mentors(self):
|
||||
course = new_course("Test Course")
|
||||
assert course.get_mentors() == []
|
||||
|
||||
def test_new_course(self):
|
||||
course = new_course("Test Course")
|
||||
assert course.title == "Test Course"
|
||||
assert course.name == "test-course"
|
||||
user = new_user("Tester", "tester@example.com")
|
||||
course.add_mentor("tester@example.com")
|
||||
|
||||
mentors = course.get_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}]
|
||||
|
||||
# disabled this test as it is failing
|
||||
def _test_add_mentors(self):
|
||||
course = new_course("Test Course")
|
||||
assert course.get_mentors() == []
|
||||
def tearDown(self):
|
||||
if frappe.db.exists("User", "tester@example.com"):
|
||||
frappe.delete_doc("User", "tester@example.com")
|
||||
|
||||
user = new_user("Tester", "tester@example.com")
|
||||
course.add_mentor("tester@example.com")
|
||||
|
||||
mentors = course.get_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}]
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
if frappe.db.exists("User", "tester@example.com"):
|
||||
frappe.delete_doc("User", "tester@example.com")
|
||||
|
||||
if frappe.db.exists("LMS Course", "test-course"):
|
||||
frappe.db.delete("Exercise Submission", {"course": "test-course"})
|
||||
frappe.db.delete("Exercise Latest Submission", {"course": "test-course"})
|
||||
frappe.db.delete("Exercise", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Batch Membership", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Batch", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Course Mentor Mapping", {"course": "test-course"})
|
||||
frappe.db.delete("Course Instructor", {"parent": "test-course"})
|
||||
frappe.db.sql('delete from `tabCourse Instructor`')
|
||||
frappe.delete_doc("LMS Course", "test-course")
|
||||
if frappe.db.exists("LMS Course", "test-course"):
|
||||
frappe.db.delete("Exercise Submission", {"course": "test-course"})
|
||||
frappe.db.delete("Exercise Latest Submission", {"course": "test-course"})
|
||||
frappe.db.delete("Exercise", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Batch Membership", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Batch", {"course": "test-course"})
|
||||
frappe.db.delete("LMS Course Mentor Mapping", {"course": "test-course"})
|
||||
frappe.db.delete("Course Instructor", {"parent": "test-course"})
|
||||
frappe.db.sql("delete from `tabCourse Instructor`")
|
||||
frappe.delete_doc("LMS Course", "test-course")
|
||||
|
||||
|
||||
def new_user(name, email):
|
||||
user = frappe.db.exists("User", email)
|
||||
if user:
|
||||
return frappe.get_doc("User", user)
|
||||
else:
|
||||
filters = {
|
||||
"doctype": "User",
|
||||
"email": email,
|
||||
"first_name": name,
|
||||
"send_welcome_email": False
|
||||
}
|
||||
user = frappe.db.exists("User", email)
|
||||
if user:
|
||||
return frappe.get_doc("User", user)
|
||||
else:
|
||||
filters = {
|
||||
"doctype": "User",
|
||||
"email": email,
|
||||
"first_name": name,
|
||||
"send_welcome_email": False,
|
||||
}
|
||||
|
||||
doc = frappe.get_doc(filters)
|
||||
doc.insert()
|
||||
return doc
|
||||
doc = frappe.get_doc(filters)
|
||||
doc.insert()
|
||||
return doc
|
||||
|
||||
|
||||
def new_course(title, additional_filters=None):
|
||||
course = frappe.db.exists("LMS Course", { "title": title })
|
||||
if course:
|
||||
return frappe.get_doc("LMS Course", course)
|
||||
else:
|
||||
create_evaluator()
|
||||
filters = {
|
||||
"doctype": "LMS Course",
|
||||
"title": title,
|
||||
"short_introduction": title,
|
||||
"description": title
|
||||
}
|
||||
course = frappe.db.exists("LMS Course", {"title": title})
|
||||
if course:
|
||||
return frappe.get_doc("LMS Course", course)
|
||||
else:
|
||||
create_evaluator()
|
||||
filters = {
|
||||
"doctype": "LMS Course",
|
||||
"title": title,
|
||||
"short_introduction": title,
|
||||
"description": title,
|
||||
}
|
||||
|
||||
if additional_filters:
|
||||
filters.update(additional_filters)
|
||||
if additional_filters:
|
||||
filters.update(additional_filters)
|
||||
|
||||
doc = frappe.get_doc(filters)
|
||||
doc.insert(ignore_permissions=True)
|
||||
return doc
|
||||
doc = frappe.get_doc(filters)
|
||||
doc.insert(ignore_permissions=True)
|
||||
return doc
|
||||
|
||||
|
||||
def create_evaluator():
|
||||
if not frappe.db.exists("Course Evaluator", "evaluator@example.com"):
|
||||
new_user("Evaluator", "evaluator@example.com")
|
||||
frappe.get_doc({
|
||||
"doctype": "Course Evaluator",
|
||||
"evaluator": "evaluator@example.com"
|
||||
}).save(ignore_permissions=True)
|
||||
if not frappe.db.exists("Course Evaluator", "evaluator@example.com"):
|
||||
new_user("Evaluator", "evaluator@example.com")
|
||||
frappe.get_doc(
|
||||
{"doctype": "Course Evaluator", "evaluator": "evaluator@example.com"}
|
||||
).save(ignore_permissions=True)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Course Enrollment', {
|
||||
frappe.ui.form.on("LMS Course Enrollment", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LMSCourseEnrollment(Document):
|
||||
pass
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLMSCourseEnrollment(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Course Interest', {
|
||||
frappe.ui.form.on("LMS Course Interest", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,16 +4,18 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LMSCourseInterest(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def capture_interest(course):
|
||||
data = {
|
||||
"doctype": "LMS Course Interest",
|
||||
"course": course,
|
||||
"user": frappe.session.user
|
||||
}
|
||||
if not frappe.db.exists(data):
|
||||
frappe.get_doc(data).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
data = {
|
||||
"doctype": "LMS Course Interest",
|
||||
"course": course,
|
||||
"user": frappe.session.user,
|
||||
}
|
||||
if not frappe.db.exists(data):
|
||||
frappe.get_doc(data).save(ignore_permissions=True)
|
||||
return "OK"
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLMSCourseInterest(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Course Mentor Mapping', {
|
||||
onload: function(frm) {
|
||||
frm.set_query('mentor', function(doc) {
|
||||
frappe.ui.form.on("LMS Course Mentor Mapping", {
|
||||
onload: function (frm) {
|
||||
frm.set_query("mentor", function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
"ignore_user_type": 1,
|
||||
}
|
||||
ignore_user_type: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LMSCourseMentorMapping(Document):
|
||||
def validate(self):
|
||||
duplicate_mapping = frappe.get_all("LMS Course Mentor Mapping",
|
||||
filters = {
|
||||
"course": self.course,
|
||||
"mentor": self.mentor
|
||||
})
|
||||
duplicate_mapping = frappe.get_all(
|
||||
"LMS Course Mentor Mapping", filters={"course": self.course, "mentor": self.mentor}
|
||||
)
|
||||
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)
|
||||
)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, FOSS United and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestLMSCourseMentorMapping(unittest.TestCase):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LMS Course Progress', {
|
||||
frappe.ui.form.on("LMS Course Progress", {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LMSCourseProgress(Document):
|
||||
pass
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user