chore: formatted files with ruff

This commit is contained in:
Jannat Patel
2025-08-11 17:48:37 +05:30
parent be31c18bfe
commit a92e04343a
96 changed files with 490 additions and 1028 deletions

124
.eslintrc Normal file
View File

@@ -0,0 +1,124 @@
{
"env": {
"browser": true,
"node": true,
"es2022": true
},
"parserOptions": {
"sourceType": "module"
},
"extends": "eslint:recommended",
"rules": {
"indent": "off",
"brace-style": "off",
"no-mixed-spaces-and-tabs": "off",
"no-useless-escape": "off",
"space-unary-ops": ["error", { "words": true }],
"linebreak-style": "off",
"quotes": ["off"],
"semi": "off",
"camelcase": "off",
"no-unused-vars": "off",
"no-console": ["warn"],
"no-extra-boolean-cast": ["off"],
"no-control-regex": ["off"],
},
"root": true,
"globals": {
"frappe": true,
"Vue": true,
"SetVueGlobals": true,
"__": true,
"repl": true,
"Class": true,
"locals": true,
"cint": true,
"cstr": true,
"cur_frm": true,
"cur_dialog": true,
"cur_page": true,
"cur_list": true,
"cur_tree": true,
"msg_dialog": true,
"is_null": true,
"in_list": true,
"has_common": true,
"posthog": true,
"has_words": true,
"validate_email": true,
"open_web_template_values_editor": true,
"validate_name": true,
"validate_phone": true,
"validate_url": true,
"get_number_format": true,
"format_number": true,
"format_currency": true,
"comment_when": true,
"open_url_post": true,
"toTitle": true,
"lstrip": true,
"rstrip": true,
"strip": true,
"strip_html": true,
"replace_all": true,
"flt": true,
"precision": true,
"CREATE": true,
"AMEND": true,
"CANCEL": true,
"copy_dict": true,
"get_number_format_info": true,
"strip_number_groups": true,
"print_table": true,
"Layout": true,
"web_form_settings": true,
"$c": true,
"$a": true,
"$i": true,
"$bg": true,
"$y": true,
"$c_obj": true,
"refresh_many": true,
"refresh_field": true,
"toggle_field": true,
"get_field_obj": true,
"get_query_params": true,
"unhide_field": true,
"hide_field": true,
"set_field_options": true,
"getCookie": true,
"getCookies": true,
"get_url_arg": true,
"md5": true,
"$": true,
"jQuery": true,
"moment": true,
"hljs": true,
"Awesomplete": true,
"Sortable": true,
"Showdown": true,
"Taggle": true,
"Gantt": true,
"Slick": true,
"Webcam": true,
"PhotoSwipe": true,
"PhotoSwipeUI_Default": true,
"io": true,
"JsBarcode": true,
"L": true,
"Chart": true,
"DataTable": true,
"Cypress": true,
"cy": true,
"it": true,
"describe": true,
"expect": true,
"context": true,
"before": true,
"beforeEach": true,
"after": true,
"qz": true,
"localforage": true,
"extend_cscript": true
}
}

View File

@@ -19,6 +19,9 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
hooks:
- id: ruff
name: "Run ruff import sorter"
args: ["--select=I", "--fix"]
- id: ruff
name: "Run ruff linter"
- id: ruff-format

View File

@@ -1,5 +1,8 @@
import { defineStore } from 'pinia'
import { createResource } from 'frappe-ui'
import { useRouter } from 'vue-router'
const router = useRouter()
export const usersStore = defineStore('lms-users', () => {
let userResource = createResource({

View File

@@ -1,5 +1,6 @@
import frappe
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
from lms.lms.api import give_discussions_permission

View File

@@ -4,9 +4,10 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_link_to_form, add_months, getdate
from frappe.utils import add_months, get_link_to_form, getdate
from frappe.utils.user import get_system_managers
from lms.lms.utils import validate_image, generate_slug
from lms.lms.utils import generate_slug, validate_image
class JobOpportunity(Document):

View File

@@ -1,40 +1,39 @@
"""API methods for the LMS.
"""
"""API methods for the LMS."""
import json
import frappe
import zipfile
import os
import re
import shutil
import xml.etree.ElementTree as ET
from frappe.translate import get_all_translations
import zipfile
from xml.dom.minidom import parseString
import frappe
from frappe import _
from frappe.utils import (
get_datetime,
cint,
flt,
now,
add_days,
format_date,
date_diff,
from frappe.integrations.frappe_providers.frappecloud_billing import (
current_site_info,
is_fc_site,
)
from frappe.query_builder import DocType
from lms.lms.utils import get_average_rating, get_lesson_count
from xml.dom.minidom import parseString
from lms.lms.doctype.course_lesson.course_lesson import save_progress
from frappe.integrations.frappe_providers.frappecloud_billing import (
is_fc_site,
current_site_info,
from frappe.translate import get_all_translations
from frappe.utils import (
add_days,
cint,
date_diff,
flt,
format_date,
get_datetime,
now,
)
from lms.lms.doctype.course_lesson.course_lesson import save_progress
from lms.lms.utils import get_average_rating, get_lesson_count
@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 = frappe.get_doc(doctype="Code Revision", section=section, code=code, author=frappe.session.user)
doc.insert()
return {"name": doc.name}
@@ -98,9 +97,7 @@ def approve_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()
):
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"
@@ -114,9 +111,7 @@ def reject_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()
):
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"
@@ -131,9 +126,7 @@ def undo_reject_cohort_join_request(join_request):
# 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()
):
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"
@@ -141,28 +134,6 @@ def undo_reject_cohort_join_request(join_request):
return {"ok": True}
@frappe.whitelist()
def add_mentor_to_subgroup(subgroup, email):
try:
sg = frappe.get_doc("Cohort Subgroup", subgroup)
except frappe.DoesNotExistError:
return {"ok": False, "error": f"Invalid subgroup: {subgroup}"}
if (
not sg.get_cohort().is_admin(frappe.session.user)
and "System Manager" not in frappe.get_roles()
):
return {"ok": False, "error": "Permission Deined"}
try:
user = frappe.get_doc("User", email)
except frappe.DoesNotExistError:
return {"ok": False, "error": f"Invalid user: {email}"}
sg.add_mentor(email)
return {"ok": True}
@frappe.whitelist(allow_guest=True)
def get_user_info():
if frappe.session.user == "Guest":
@@ -178,9 +149,7 @@ def get_user_info():
user.is_instructor = "Course Creator" in user.roles
user.is_moderator = "Moderator" in user.roles
user.is_evaluator = "Batch Evaluator" in user.roles
user.is_student = (
not user.is_instructor and not user.is_moderator and not user.is_evaluator
)
user.is_student = not user.is_instructor and not user.is_moderator and not user.is_evaluator
user.is_fc_site = is_fc_site()
user.is_system_manager = "System Manager" in user.roles
user.sitename = frappe.local.site
@@ -218,17 +187,13 @@ def validate_billing_access(billing_type, name):
message = _("Module Name is incorrect or does not exist.")
if access and billing_type == "course":
membership = frappe.db.exists(
"LMS Enrollment", {"member": frappe.session.user, "course": name}
)
membership = frappe.db.exists("LMS Enrollment", {"member": frappe.session.user, "course": name})
if membership:
access = False
message = _("You are already enrolled for this course.")
elif access and billing_type == "batch":
membership = frappe.db.exists(
"LMS Batch Enrollment", {"member": frappe.session.user, "batch": name}
)
membership = frappe.db.exists("LMS Batch Enrollment", {"member": frappe.session.user, "batch": name})
if membership:
access = False
message = _("You are already enrolled for this batch.")
@@ -339,12 +304,8 @@ def get_chart_details():
"upcoming": 0,
},
)
details.users = frappe.db.count(
"User", {"enabled": 1, "name": ["not in", ("Administrator", "Guest")]}
)
details.completions = frappe.db.count(
"LMS Enrollment", {"progress": ["like", "%100%"]}
)
details.users = frappe.db.count("User", {"enabled": 1, "name": ["not in", ("Administrator", "Guest")]})
details.completions = frappe.db.count("LMS Enrollment", {"progress": ["like", "%100%"]})
details.certifications = frappe.db.count("LMS Certificate", {"published": 1})
return details
@@ -376,7 +337,7 @@ def get_branding():
@frappe.whitelist()
def get_unsplash_photos(keyword=None):
from lms.unsplash import get_list, get_by_keyword
from lms.unsplash import get_by_keyword, get_list
if keyword:
return get_by_keyword(keyword)
@@ -455,18 +416,14 @@ def get_count_of_certified_members(filters=None):
Certificate = DocType("LMS Certificate")
query = (
frappe.qb.from_(Certificate)
.select(Certificate.member)
.distinct()
.where(Certificate.published == 1)
frappe.qb.from_(Certificate).select(Certificate.member).distinct().where(Certificate.published == 1)
)
if filters:
for field, value in filters.items():
if field == "category":
query = query.where(
Certificate.course_title.like(f"%{value}%")
| Certificate.batch_title.like(f"%{value}%")
Certificate.course_title.like(f"%{value}%") | Certificate.batch_title.like(f"%{value}%")
)
elif field == "member_name":
query = query.where(Certificate.member_name.like(value[1]))
@@ -504,9 +461,7 @@ def get_assigned_badges(member):
)
for badge in assigned_badges:
badge.update(
frappe.db.get_value("LMS Badge", badge.badge, ["name", "title", "image"])
)
badge.update(frappe.db.get_value("LMS Badge", badge.badge, ["name", "title", "image"]))
return assigned_badges
@@ -692,9 +647,7 @@ def update_chapter_index(chapter, course, idx):
chapters.insert(idx, chapter)
for i, chapter_name in enumerate(chapters):
frappe.db.set_value(
"Chapter Reference", {"chapter": chapter_name, "parent": course}, "idx", i + 1
)
frappe.db.set_value("Chapter Reference", {"chapter": chapter_name, "parent": course}, "idx", i + 1)
@frappe.whitelist(allow_guest=True)
@@ -717,7 +670,6 @@ def get_categories(doctype, filters):
@frappe.whitelist()
def get_members(start=0, search=""):
filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]}
or_filters = {}
@@ -784,9 +736,7 @@ def save_evaluation_details(
"""
Save evaluation details for a member against a course.
"""
evaluation = frappe.db.exists(
"LMS Certificate Evaluation", {"member": member, "course": course}
)
evaluation = frappe.db.exists("LMS Certificate Evaluation", {"member": member, "course": course})
details = {
"date": date,
@@ -923,9 +873,7 @@ def update_course_statistics():
for course in courses:
lessons = get_lesson_count(course.name)
enrollments = frappe.db.count(
"LMS Enrollment", {"course": course.name, "member_type": "Student"}
)
enrollments = frappe.db.count("LMS Enrollment", {"course": course.name, "member_type": "Student"})
avg_rating = get_average_rating(course.name) or 0
avg_rating = flt(avg_rating, frappe.get_system_settings("float_precision") or 3)
@@ -958,28 +906,21 @@ def get_announcements(batch):
)
for communication in communications:
communication.image = frappe.get_cached_value(
"User", communication.sender, "user_image"
)
communication.image = frappe.get_cached_value("User", communication.sender, "user_image")
return communications
@frappe.whitelist()
def delete_course(course):
chapters = frappe.get_all("Course Chapter", {"course": course}, pluck="name")
chapter_references = frappe.get_all(
"Chapter Reference", {"parent": course}, pluck="name"
)
chapter_references = frappe.get_all("Chapter Reference", {"parent": course}, pluck="name")
for chapter in chapters:
lessons = frappe.get_all("Course Lesson", {"chapter": chapter}, pluck="name")
lesson_references = frappe.get_all(
"Lesson Reference", {"parent": chapter}, pluck="name"
)
lesson_references = frappe.get_all("Lesson Reference", {"parent": chapter}, pluck="name")
for lesson in lesson_references:
frappe.delete_doc("Lesson Reference", lesson)
@@ -1055,9 +996,7 @@ def give_discussions_permission():
@frappe.whitelist()
def upsert_chapter(title, course, is_scorm_package, scorm_package, name=None):
values = frappe._dict(
{"title": title, "course": course, "is_scorm_package": is_scorm_package}
)
values = frappe._dict({"title": title, "course": course, "is_scorm_package": is_scorm_package})
if is_scorm_package:
scorm_package = frappe._dict(scorm_package)
@@ -1115,14 +1054,12 @@ def check_for_malicious_code(zip_path):
content = file.read().decode("utf-8", errors="ignore")
for pattern in suspicious_patterns:
if re.search(pattern, content):
frappe.throw(
_("Suspicious pattern found in {0}: {1}").format(file_name, pattern)
)
frappe.throw(_("Suspicious pattern found in {0}: {1}").format(file_name, pattern))
def get_manifest_file(extract_path):
manifest_file = None
for root, dirs, files in os.walk(extract_path):
for root, _dirs, files in os.walk(extract_path):
for file in files:
if file == "imsmanifest.xml":
manifest_file = os.path.join(root, file)
@@ -1201,9 +1138,7 @@ def delete_scorm_package(scorm_package_path):
@frappe.whitelist()
def mark_lesson_progress(course, chapter_number, lesson_number):
chapter_name = frappe.get_value(
"Chapter Reference", {"parent": course, "idx": chapter_number}, "chapter"
)
chapter_name = frappe.get_value("Chapter Reference", {"parent": course, "idx": chapter_number}, "chapter")
lesson_name = frappe.get_value(
"Lesson Reference", {"parent": chapter_name, "idx": lesson_number}, "lesson"
)
@@ -1218,9 +1153,7 @@ def get_heatmap_data(member=None, base_days=200):
base_date, start_date, number_of_days, days = calculate_date_ranges(base_days)
date_count = initialize_date_count(days)
lesson_completions, quiz_submissions, assignment_submissions = fetch_activity_data(
member, start_date
)
lesson_completions, quiz_submissions, assignment_submissions = fetch_activity_data(member, start_date)
count_dates(lesson_completions, date_count)
count_dates(quiz_submissions, date_count)
count_dates(assignment_submissions, date_count)
@@ -1311,13 +1244,11 @@ def prepare_heatmap_data(start_date, number_of_days, date_count):
labels[column_index] = current_month
last_seen_month = current_month
for (index, label) in enumerate(labels):
for index, label in enumerate(labels):
if not label:
labels[index] = ""
formatted_heatmap_data = [
{"name": day, "data": heatmap_data[day]} for day in days_of_week
]
formatted_heatmap_data = [{"name": day, "data": heatmap_data[day]} for day in days_of_week]
total_activities = sum(date_count.values())
return formatted_heatmap_data, labels, total_activities, week_count
@@ -1371,10 +1302,7 @@ def cancel_evaluation(evaluation):
info = frappe.db.get_value("Event", event.parent, ["starts_on", "subject"], as_dict=1)
date = str(info.starts_on).split(" ")[0]
if (
date == str(evaluation.date.format("YYYY-MM-DD"))
and evaluation.member_name in info.subject
):
if date == str(evaluation.date.format("YYYY-MM-DD")) and evaluation.member_name in info.subject:
communication = frappe.db.get_value(
"Communication",
{"reference_doctype": "Event", "reference_name": event.parent},
@@ -1577,9 +1505,7 @@ def make_new_exercise_submission(exercise, code, test_cases):
def update_exercise_submission(submission, code, test_cases):
update_test_cases(test_cases, submission)
status = get_exercise_status(test_cases)
frappe.db.set_value(
"LMS Programming Exercise Submission", submission, {"status": status, "code": code}
)
frappe.db.set_value("LMS Programming Exercise Submission", submission, {"status": status, "code": code})
def get_exercise_status(test_cases):

View File

@@ -31,9 +31,7 @@ class CohortSubgroup(Document):
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"
)
return frappe.get_all("Cohort Join Request", filters=q, fields=["*"], order_by="creation desc")
def get_mentors(self):
emails = frappe.get_all(

View File

@@ -3,8 +3,9 @@
import frappe
from frappe.model.document import Document
from lms.lms.utils import get_course_progress
from lms.lms.api import update_course_statistics
from lms.lms.utils import get_course_progress
class CourseChapter(Document):
@@ -13,15 +14,11 @@ class CourseChapter(Document):
update_course_statistics()
def recalculate_course_progress(self):
previous_lessons = (
self.get_doc_before_save() and self.get_doc_before_save().as_dict().lessons
)
previous_lessons = self.get_doc_before_save() and self.get_doc_before_save().as_dict().lessons
current_lessons = self.lessons
if previous_lessons and previous_lessons != current_lessons:
enrolled_members = frappe.get_all(
"LMS Enrollment", {"course": self.course}, ["member", "name"]
)
enrolled_members = frappe.get_all("LMS Enrollment", {"course": self.course}, ["member", "name"])
for enrollment in enrolled_members:
new_progress = get_course_progress(self.course, enrollment.member)
frappe.db.set_value("LMS Enrollment", enrollment.name, "progress", new_progress)

View File

@@ -1,13 +1,15 @@
# Copyright (c) 2022, Frappe and contributors
# For license information, please see license.txt
from datetime import datetime
import frappe
from frappe import _
from frappe.model.document import Document
from lms.lms.utils import get_evaluator
from datetime import datetime
from frappe.utils import get_time, getdate
from lms.lms.utils import get_evaluator
class CourseEvaluator(Document):
def validate(self):
@@ -42,17 +44,9 @@ class CourseEvaluator(Document):
overlap = False
for slot in same_day_slots:
if (
get_time(schedule.start_time)
<= get_time(slot.start_time)
< get_time(schedule.end_time)
):
if get_time(schedule.start_time) <= get_time(slot.start_time) < get_time(schedule.end_time):
overlap = True
if (
get_time(schedule.start_time)
< get_time(slot.end_time)
<= get_time(schedule.end_time)
):
if get_time(schedule.start_time) < get_time(slot.end_time) <= get_time(schedule.end_time):
overlap = True
if get_time(slot.start_time) < get_time(schedule.start_time) and get_time(
schedule.end_time
@@ -85,9 +79,7 @@ def get_schedule(course, date, batch=None):
)
for slot in booked_slots:
same_slot = list(
filter(lambda x: x.start_time == slot.start_time and x.day == slot.day, all_slots)
)
same_slot = list(filter(lambda x: x.start_time == slot.start_time and x.day == slot.day, all_slots))
if len(same_slot):
all_slots.remove(same_slot[0])

View File

@@ -1,14 +1,17 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils.telemetry import capture
from lms.lms.utils import get_course_progress
from ...md import find_macros
from frappe.realtime import get_website_room
from frappe.utils.telemetry import capture
from lms.lms.utils import get_course_progress
from ...md import find_macros
class CourseLesson(Document):
@@ -44,9 +47,7 @@ class CourseLesson(Document):
@frappe.whitelist()
def save_progress(lesson, course):
membership = frappe.db.exists(
"LMS Enrollment", {"course": course, "member": frappe.session.user}
)
membership = frappe.db.exists("LMS Enrollment", {"course": course, "member": frappe.session.user})
if not membership:
return 0
@@ -93,9 +94,7 @@ def capture_progress_for_analytics(progress, course):
def get_quiz_progress(lesson):
lesson_details = frappe.db.get_value(
"Course Lesson", lesson, ["body", "content"], as_dict=1
)
lesson_details = frappe.db.get_value("Course Lesson", lesson, ["body", "content"], as_dict=1)
quizzes = []
if lesson_details.content:
@@ -129,9 +128,7 @@ def get_quiz_progress(lesson):
def get_assignment_progress(lesson):
lesson_details = frappe.db.get_value(
"Course Lesson", lesson, ["body", "content"], as_dict=1
)
lesson_details = frappe.db.get_value("Course Lesson", lesson, ["body", "content"], as_dict=1)
assignments = []
if lesson_details.content:

View File

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

View File

@@ -1,88 +0,0 @@
{
"actions": [],
"creation": "2021-04-29 16:29:56.857914",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"invite_email",
"signup_email",
"column_break_4",
"status",
"full_name",
"username",
"invite_code"
],
"fields": [
{
"allow_in_quick_entry": 1,
"fieldname": "invite_email",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Invite Email",
"options": "Email",
"unique": 1
},
{
"fieldname": "full_name",
"fieldtype": "Data",
"label": "Full Name"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fieldname": "signup_email",
"fieldtype": "Data",
"label": "Signup Email",
"options": "Email"
},
{
"fieldname": "username",
"fieldtype": "Data",
"label": "Username"
},
{
"fieldname": "invite_code",
"fieldtype": "Data",
"label": "Invite Code"
},
{
"default": "Pending",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
"options": "Pending\nApproved\nRejected\nRegistered"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-05-03 09:22:20.954921",
"modified_by": "Administrator",
"module": "LMS",
"name": "Invite Request",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"search_fields": "invite_email, signup_email",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "invite_email",
"track_changes": 1
}

View File

@@ -1,96 +0,0 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import json
import frappe
from frappe import _
from frappe.model.document import Document
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"
and not frappe.flags.in_test
):
self.send_email()
def create_user(self, password):
full_name_split = self.full_name.split(" ")
user = frappe.get_doc(
{
"doctype": "User",
"email": self.signup_email,
"first_name": full_name_split[0],
"last_name": full_name_split[1] if len(full_name_split) > 1 else "",
"username": self.username,
"send_welcome_email": 0,
"user_type": "Website User",
"new_password": password,
}
)
user.save(ignore_permissions=True)
return user
def send_email(self):
site_name = "Mon.School"
subject = _("Welcome to {0}!").format(site_name)
args = {
"full_name": self.full_name,
"signup_form_link": 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,
)
@frappe.whitelist(allow_guest=True)
def create_invite_request(invite_email):
if not frappe.utils.validate_email_address(invite_email):
return "invalid email"
if frappe.db.exists("User", invite_email):
return "user"
if frappe.db.exists("Invite Request", {"invite_email": invite_email}):
return "invite"
frappe.get_doc(
{"doctype": "Invite Request", "invite_email": invite_email, "status": "Approved"}
).save(ignore_permissions=True)
return "OK"
@frappe.whitelist(allow_guest=True)
def update_invite(data):
data = frappe._dict(json.loads(data)) if type(data) == str else frappe._dict(data)
try:
doc = frappe.get_doc("Invite Request", data.invite_code)
except frappe.DoesNotExistError:
frappe.throw(_("Invalid Invite Code."))
doc.signup_email = data.signup_email
doc.username = data.username
doc.full_name = data.full_name
doc.invite_code = data.invite_code
doc.save(ignore_permissions=True)
user = doc.create_user(data.password)
if user:
doc.status = "Registered"
doc.save(ignore_permissions=True)
return "OK"

View File

@@ -1,14 +0,0 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
import unittest
import frappe
from lms.lms.doctype.invite_request.invite_request import (
create_invite_request,
update_invite,
)
class TestInviteRequest(unittest.TestCase):
pass

View File

@@ -3,7 +3,8 @@
import frappe
from frappe.model.document import Document
from lms.lms.utils import has_course_moderator_role, has_course_instructor_role
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role
class LMSAssignment(Document):

View File

@@ -3,9 +3,9 @@
import frappe
from frappe import _
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
from frappe.model.document import Document
from frappe.utils import validate_url
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
class LMSAssignmentSubmission(Document):
@@ -21,9 +21,7 @@ class LMSAssignmentSubmission(Document):
):
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
)
_("Assignment for Lesson {0} by {1} already exists.").format(lesson_title, self.member_name)
)
def validate_url(self):
@@ -33,17 +31,15 @@ class LMSAssignmentSubmission(Document):
def validate_status(self):
if not self.is_new():
doc_before_save = self.get_doc_before_save()
if (
doc_before_save.status != self.status or doc_before_save.comments != self.comments
):
if doc_before_save.status != self.status or doc_before_save.comments != self.comments:
self.trigger_update_notification()
def trigger_update_notification(self):
notification = frappe._dict(
{
"subject": _(
"There has been an update on your submission for assignment {0}"
).format(self.assignment_title),
"subject": _("There has been an update on your submission for assignment {0}").format(
self.assignment_title
),
"email_content": self.comments,
"document_type": self.doctype,
"document_name": self.name,

View File

@@ -1,10 +1,11 @@
# Copyright (c) 2024, Frappe and contributors
# For license information, please see license.txt
import frappe
import json
from frappe.model.document import Document
import frappe
from frappe import _
from frappe.model.document import Document
class LMSBadge(Document):
@@ -27,7 +28,7 @@ class LMSBadge(Document):
def rule_condition_satisfied(self, doc):
doc_before_save = doc.get_doc_before_save()
if self.event == "New" and doc_before_save != None:
if self.event == "New" and doc_before_save is not None:
return False
if self.condition:

View File

@@ -1,21 +1,23 @@
# Copyright (c) 2022, Frappe and contributors
# For license information, please see license.txt
import frappe
import requests
import base64
import json
from frappe import _
from datetime import timedelta
import frappe
import requests
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, format_datetime, get_time, add_days, nowdate
from frappe.utils import add_days, cint, format_datetime, get_time, nowdate
from lms.lms.utils import (
generate_slug,
get_assignment_details,
get_lesson_index,
get_lesson_url,
get_quiz_details,
get_assignment_details,
update_payment_record,
generate_slug,
)
@@ -50,9 +52,7 @@ class LMSBatch(Document):
duplicates = {course for course in courses if courses.count(course) > 1}
if len(duplicates):
title = frappe.db.get_value("LMS Course", next(iter(duplicates)), "title")
frappe.throw(
_("Course {0} has already been added to this batch.").format(frappe.bold(title))
)
frappe.throw(_("Course {0} has already been added to this batch.").format(frappe.bold(title)))
def validate_payments_app(self):
if self.paid_batch:
@@ -73,13 +73,9 @@ class LMSBatch(Document):
assessments = [row.assessment_name for row in self.assessment]
for assessment in self.assessment:
if assessments.count(assessment.assessment_name) > 1:
title = frappe.db.get_value(
assessment.assessment_type, assessment.assessment_name, "title"
)
title = frappe.db.get_value(assessment.assessment_type, assessment.assessment_name, "title")
frappe.throw(
_("Assessment {0} has already been added to this batch.").format(
frappe.bold(title)
)
_("Assessment {0} has already been added to this batch.").format(frappe.bold(title))
)
def validate_evaluation_end_date(self):
@@ -90,9 +86,7 @@ class LMSBatch(Document):
members = frappe.get_all("LMS Batch Enrollment", {"batch": self.name}, pluck="member")
for course in self.courses:
for member in members:
if not frappe.db.exists(
"LMS Enrollment", {"course": course.course, "member": member}
):
if not frappe.db.exists("LMS Enrollment", {"course": course.course, "member": member}):
enrollment = frappe.new_doc("LMS Enrollment")
enrollment.course = course.course
enrollment.member = member
@@ -122,9 +116,7 @@ class LMSBatch(Document):
schedule.start_time
) > get_time(self.end_time):
frappe.throw(
_("Row #{0} Start time cannot be outside the batch duration.").format(
schedule.idx
)
_("Row #{0} Start time cannot be outside the batch duration.").format(schedule.idx)
)
if get_time(schedule.end_time) < get_time(self.start_time) or get_time(
@@ -135,9 +127,7 @@ class LMSBatch(Document):
)
if schedule.date < self.start_date or schedule.date > self.end_date:
frappe.throw(
_("Row #{0} Date cannot be outside the batch duration.").format(schedule.idx)
)
frappe.throw(_("Row #{0} Date cannot be outside the batch duration.").format(schedule.idx))
def on_payment_authorized(self, payment_status):
if payment_status in ["Authorized", "Completed"]:
@@ -163,9 +153,7 @@ def create_live_class(
"duration": duration,
"agenda": description,
"private_meeting": True,
"auto_recording": "none"
if auto_recording == "No Recording"
else auto_recording.lower(),
"auto_recording": "none" if auto_recording == "No Recording" else auto_recording.lower(),
"timezone": timezone,
}
headers = {
@@ -200,9 +188,7 @@ def create_live_class(
class_details.save()
return class_details
else:
frappe.throw(
_("Error creating live class. Please try again. {0}").format(response.text)
)
frappe.throw(_("Error creating live class. Please try again. {0}").format(response.text))
def authenticate(zoom_account):
@@ -210,15 +196,15 @@ def authenticate(zoom_account):
if not zoom.enabled:
frappe.throw(_("Please enable the zoom account to use this feature."))
authenticate_url = f"https://zoom.us/oauth/token?grant_type=account_credentials&account_id={zoom.account_id}"
authenticate_url = (
f"https://zoom.us/oauth/token?grant_type=account_credentials&account_id={zoom.account_id}"
)
headers = {
"Authorization": "Basic "
+ base64.b64encode(
bytes(
zoom.client_id
+ ":"
+ zoom.get_password(fieldname="client_secret", raise_exception=False),
zoom.client_id + ":" + zoom.get_password(fieldname="client_secret", raise_exception=False),
encoding="utf8",
)
).decode()
@@ -273,15 +259,11 @@ def get_live_classes(batch):
def get_timetable_details(timetable):
for entry in timetable:
entry.title = frappe.db.get_value(
entry.reference_doctype, entry.reference_docname, "title"
)
entry.title = frappe.db.get_value(entry.reference_doctype, entry.reference_docname, "title")
assessment = frappe._dict({"assessment_name": entry.reference_docname})
if entry.reference_doctype == "Course Lesson":
course = frappe.db.get_value(
entry.reference_doctype, entry.reference_docname, "course"
)
course = frappe.db.get_value(entry.reference_doctype, entry.reference_docname, "course")
entry.url = get_lesson_url(course, get_lesson_index(entry.reference_docname))
entry.completed = (
@@ -306,43 +288,6 @@ def get_timetable_details(timetable):
return timetable
@frappe.whitelist()
def is_milestone_complete(idx, batch):
previous_rows = frappe.get_all(
"LMS Batch Timetable",
filters={"parent": batch, "idx": ["<", cint(idx)]},
fields=["reference_doctype", "reference_docname", "idx"],
order_by="idx",
)
for row in previous_rows:
if row.reference_doctype == "Course Lesson":
if not frappe.db.exists(
"LMS Course Progress",
{"member": frappe.session.user, "lesson": row.reference_docname},
):
return False
if row.reference_doctype == "LMS Quiz":
passing_percentage = frappe.db.get_value(
row.reference_doctype, row.reference_docname, "passing_percentage"
)
if not frappe.db.exists(
"LMS Quiz Submission",
{"quiz": row.reference_docname, "member": frappe.session.user},
):
return False
if row.reference_doctype == "LMS Assignment":
if not frappe.db.exists(
"LMS Assignment Submission",
{"assignment": row.reference_docname, "member": frappe.session.user},
):
return False
return True
def send_batch_start_reminder():
batches = frappe.get_all(
"LMS Batch",
@@ -351,9 +296,7 @@ def send_batch_start_reminder():
)
for batch in batches:
students = frappe.get_all(
"LMS Batch Enrollment", {"batch": batch.name}, ["member", "member_name"]
)
students = frappe.get_all("LMS Batch Enrollment", {"batch": batch.name}, ["member", "member_name"])
for student in students:
send_mail(batch, student)

View File

@@ -1,11 +1,12 @@
# Copyright (c) 2025, Frappe and contributors
# For license information, please see license.txt
import frappe
import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.email.doctype.email_template.email_template import get_email_template
from frappe.model.document import Document
class LMSBatchEnrollment(Document):
@@ -25,9 +26,7 @@ class LMSBatchEnrollment(Document):
frappe.throw(_("Member already enrolled in this batch"))
def validate_course_enrollment(self):
courses = frappe.get_all(
"Batch Course", filters={"parent": self.batch}, fields=["course"]
)
courses = frappe.get_all("Batch Course", filters={"parent": self.batch}, fields=["course"])
for course in courses:
if not frappe.db.exists(
@@ -40,9 +39,7 @@ class LMSBatchEnrollment(Document):
enrollment.save()
def add_member_to_live_class(self):
live_classes = frappe.get_all(
"LMS Live Class", {"batch_name": self.batch}, ["name", "event"]
)
live_classes = frappe.get_all("LMS Live Class", {"batch_name": self.batch}, ["name", "event"])
for live_class in live_classes:
if live_class.event:
@@ -68,9 +65,7 @@ def send_confirmation_email(doc):
outgoing_email_account = frappe.get_cached_value(
"Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name"
)
if not doc.confirmation_email_sent and (
outgoing_email_account or frappe.conf.get("mail_login")
):
if not doc.confirmation_email_sent and (outgoing_email_account or frappe.conf.get("mail_login")):
send_mail(doc)
frappe.db.set_value(doc.doctype, doc.name, "confirmation_email_sent", 1)

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -63,9 +63,7 @@ def save_message(message, batch):
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 Enrollment", filters={"course": course_name, "member": email}
)
membership = frappe.get_last_doc("LMS Enrollment", filters={"course": course_name, "member": email})
batch = frappe.get_doc("LMS Batch Old", batch_name)
if not batch:

View File

@@ -3,11 +3,12 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import add_years, nowdate
from lms.lms.utils import is_certified
from frappe.email.doctype.email_template.email_template import get_email_template
from frappe.model.document import Document
from frappe.model.naming import make_autoname
from frappe.utils import add_years, nowdate
from lms.lms.utils import is_certified
class LMSCertificate(Document):

View File

@@ -5,6 +5,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from lms.lms.utils import has_course_moderator_role

View File

@@ -1,22 +1,24 @@
# Copyright (c) 2022, Frappe and contributors
# For license information, please see license.txt
import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.utils import (
add_to_date,
format_date,
format_time,
getdate,
add_to_date,
get_datetime,
nowtime,
get_time,
get_fullname,
get_time,
getdate,
nowtime,
)
from lms.lms.utils import get_evaluator
import json
class LMSCertificateRequest(Document):
@@ -86,9 +88,7 @@ class LMSCertificateRequest(Document):
if (
req.date == getdate(self.date)
or getdate() < getdate(req.date)
or (
getdate() == getdate(req.date) and get_time(nowtime()) < get_time(req.start_time)
)
or (getdate() == getdate(req.date) and get_time(nowtime()) < get_time(req.start_time))
):
course_title = frappe.db.get_value("LMS Course", req.course, "title")
frappe.throw(
@@ -98,16 +98,12 @@ class LMSCertificateRequest(Document):
course_title,
)
)
if getdate() == getdate(self.date) and get_time(self.start_time) < get_time(
nowtime()
):
if getdate() == getdate(self.date) and get_time(self.start_time) < get_time(nowtime()):
frappe.throw(_("You cannot schedule evaluations for past slots."))
def validate_evaluation_end_date(self):
if self.batch_name:
evaluation_end_date = frappe.db.get_value(
"LMS Batch", self.batch_name, "evaluation_end_date"
)
evaluation_end_date = frappe.db.get_value("LMS Batch", self.batch_name, "evaluation_end_date")
if evaluation_end_date:
if getdate(self.date) > getdate(evaluation_end_date):
@@ -166,9 +162,7 @@ def setup_calendar_event(eval):
if isinstance(eval, str):
eval = frappe._dict(json.loads(eval))
calendar = frappe.db.get_value(
"Google Calendar", {"user": eval.evaluator, "enable": 1}, "name"
)
calendar = frappe.db.get_value("Google Calendar", {"user": eval.evaluator, "enable": 1}, "name")
if calendar:
event = create_event(eval)
@@ -218,15 +212,11 @@ def update_meeting_details(eval, event, calendar):
event.save()
event.reload()
frappe.db.set_value(
"LMS Certificate Request", eval.name, "google_meet_link", event.google_meet_link
)
frappe.db.set_value("LMS Certificate Request", eval.name, "google_meet_link", event.google_meet_link)
@frappe.whitelist()
def create_certificate_request(
course, date, day, start_time, end_time, batch_name=None
):
def create_certificate_request(course, date, day, start_time, end_time, batch_name=None):
is_member = frappe.db.exists(
{"doctype": "LMS Enrollment", "course": course, "member": frappe.session.user}
)

View File

@@ -3,12 +3,15 @@
import json
import random
import frappe
from frappe.model.document import Document
from frappe.utils import today, cint
from lms.lms.utils import get_chapters
from ...utils import generate_slug, validate_image, update_payment_record
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, today
from lms.lms.utils import get_chapters
from ...utils import generate_slug, update_payment_record, validate_image
class LMSCourse(Document):
@@ -60,9 +63,7 @@ class LMSCourse(Document):
def validate_certification(self):
if self.enable_certification and self.paid_certificate:
frappe.throw(
_("A course cannot have both paid certificate and certificate of completion.")
)
frappe.throw(_("A course cannot have both paid certificate and certificate of completion."))
if self.paid_certificate and not self.evaluator:
frappe.throw(_("Evaluator is required for paid certificates."))
@@ -101,9 +102,7 @@ class LMSCourse(Document):
update_payment_record("LMS Course", self.name)
def send_email_to_interested_users(self):
interested_users = frappe.get_all(
"LMS Course Interest", {"course": self.name}, ["name", "user"]
)
interested_users = frappe.get_all("LMS Course Interest", {"course": self.name}, ["name", "user"])
subject = self.title + " is available!"
args = {
"title": self.title,
@@ -122,9 +121,7 @@ class LMSCourse(Document):
args=args,
now=True,
)
frappe.enqueue(
method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args
)
frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
frappe.db.set_value("LMS Course Interest", user.name, "email_sent", True)
def autoname(self):
@@ -139,9 +136,7 @@ class LMSCourse(Document):
if not email or email == "Guest":
return False
mapping = frappe.get_all(
"LMS Course Mentor Mapping", {"course": self.name, "mentor": email}
)
mapping = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name, "mentor": email})
return mapping != []
def add_mentor(self, email):
@@ -155,9 +150,7 @@ class LMSCourse(Document):
if self.has_mentor(email):
return
doc = frappe.get_doc(
{"doctype": "LMS Course Mentor Mapping", "course": self.name, "mentor": email}
)
doc = frappe.get_doc({"doctype": "LMS Course Mentor Mapping", "course": self.name, "mentor": email})
doc.insert()
def get_student_batch(self, email):
@@ -213,9 +206,7 @@ class LMSCourse(Document):
"LMS Enrollment", {"member": member, "course": self.name}, ["batch_old"]
)
for membership in all_memberships:
membership.batch_title = frappe.db.get_value(
"LMS Batch Old", membership.batch_old, "title"
)
membership.batch_title = frappe.db.get_value("LMS Batch Old", membership.batch_old, "title")
return all_memberships

View File

@@ -18,13 +18,11 @@ class TestLMSCourse(unittest.TestCase):
course = new_course("Test Course")
assert course.get_mentors() == []
user = new_user("Tester", "tester@example.com")
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
]
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):
@@ -95,6 +93,6 @@ def new_course(title, additional_filters=None):
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)
frappe.get_doc({"doctype": "Course Evaluator", "evaluator": "evaluator@example.com"}).save(
ignore_permissions=True
)

View File

@@ -12,6 +12,4 @@ class LMSCourseMentorMapping(Document):
"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))

View File

@@ -3,6 +3,7 @@
import frappe
from frappe.model.document import Document
from lms.lms.utils import get_course_progress

View File

@@ -11,9 +11,7 @@ class LMSCourseReview(Document):
self.validate_if_already_reviewed()
def validate_if_already_reviewed(self):
if frappe.db.exists(
"LMS Course Review", {"course": self.course, "owner": self.owner}
):
if frappe.db.exists("LMS Course Review", {"course": self.course, "owner": self.owner}):
frappe.throw(frappe._("You have already reviewed this course"))

View File

@@ -60,15 +60,11 @@ class LMSEnrollment(Document):
)
def update_program_progress(self):
programs = frappe.get_all(
"LMS Program Member", {"member": self.member}, ["parent", "name"]
)
programs = frappe.get_all("LMS Program Member", {"member": self.member}, ["parent", "name"])
for program in programs:
total_progress = 0
courses = frappe.get_all(
"LMS Program Course", {"parent": program.parent}, pluck="course"
)
courses = frappe.get_all("LMS Program Course", {"parent": program.parent}, pluck="course")
for course in courses:
progress = frappe.db.get_value(
"LMS Enrollment", {"course": course, "member": self.member}, "progress"
@@ -81,9 +77,7 @@ class LMSEnrollment(Document):
@frappe.whitelist()
def create_membership(
course, batch=None, member=None, member_type="Student", role="Member"
):
def create_membership(course, batch=None, member=None, member_type="Student", role="Member"):
if frappe.db.get_value("LMS Course", course, "disable_self_learning"):
return False
@@ -104,14 +98,10 @@ def create_membership(
@frappe.whitelist()
def update_current_membership(batch, course, member):
all_memberships = frappe.get_all(
"LMS Enrollment", {"member": member, "course": course}
)
all_memberships = frappe.get_all("LMS Enrollment", {"member": member, "course": course})
for membership in all_memberships:
frappe.db.set_value("LMS Enrollment", membership.name, "is_current", 0)
current_membership = frappe.get_all(
"LMS Enrollment", {"batch_old": batch, "member": member}
)
current_membership = frappe.get_all("LMS Enrollment", {"batch_old": batch, "member": member})
if len(current_membership):
frappe.db.set_value("LMS Enrollment", current_membership[0].name, "is_current", 1)

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -1,21 +1,21 @@
# Copyright (c) 2023, Frappe and contributors
# For license information, please see license.txt
import json
from datetime import timedelta
import frappe
import requests
import json
from frappe import _
from frappe.model.document import Document
from datetime import timedelta
from frappe.utils import cint, get_datetime, format_date, nowdate, format_time
from frappe.utils import cint, format_date, format_time, get_datetime, nowdate
from lms.lms.doctype.lms_batch.lms_batch import authenticate
class LMSLiveClass(Document):
def after_insert(self):
calendar = frappe.db.get_value(
"Google Calendar", {"user": frappe.session.user, "enable": 1}, "name"
)
calendar = frappe.db.get_value("Google Calendar", {"user": frappe.session.user, "enable": 1}, "name")
if calendar:
event = self.create_event()
@@ -37,9 +37,7 @@ class LMSLiveClass(Document):
return event
def add_event_participants(self, event, calendar):
participants = frappe.get_all(
"LMS Batch Enrollment", {"batch": self.batch_name}, pluck="member"
)
participants = frappe.get_all("LMS Batch Enrollment", {"batch": self.batch_name}, pluck="member")
participants.append(frappe.session.user)
for participant in participants:

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -9,7 +9,6 @@ from frappe.model.document import Document
class LMSMentorRequest(Document):
def on_update(self):
if self.has_value_changed("status"):
if self.status == "Approved":
self.create_course_mentor_mapping()
@@ -49,18 +48,14 @@ class LMSMentorRequest(Document):
"header": email_template.subject,
"message": message,
}
frappe.enqueue(
method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args
)
frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
def send_status_change_email(self):
email_template = self.get_email_template("mentor_request_status_update")
if not email_template:
return
course_details = frappe.db.get_value(
"LMS Course", self.course, ["owner", "title"], as_dict=True
)
course_details = frappe.db.get_value("LMS Course", self.course, ["owner", "title"], as_dict=True)
message = frappe.render_template(
email_template.response,
{
@@ -78,9 +73,7 @@ class LMSMentorRequest(Document):
"header": email_template.subject,
"message": message,
}
frappe.enqueue(
method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args
)
frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
elif self.status == "Withdrawn":
email_args = {
@@ -89,9 +82,7 @@ class LMSMentorRequest(Document):
"header": email_template.subject,
"message": message,
}
frappe.enqueue(
method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args
)
frappe.enqueue(method=frappe.sendmail, queue="short", timeout=300, is_async=True, **email_args)
def get_email_template(self, template_name):
template = frappe.db.get_single_value("LMS Settings", template_name)

View File

@@ -3,9 +3,9 @@
import frappe
from frappe import _
from frappe.utils import add_days, nowdate
from frappe.email.doctype.email_template.email_template import get_email_template
from frappe.model.document import Document
from frappe.utils import add_days, nowdate
class LMSPayment(Document):
@@ -56,12 +56,8 @@ def has_paid_later(payment):
def is_batch_sold_out(payment):
if payment.payment_for_document_type == "LMS Batch":
seat_count = frappe.get_cached_value(
"LMS Batch", payment.payment_for_document, "seat_count"
)
number_of_students = frappe.db.count(
"LMS Batch Enrollment", {"batch": payment.payment_for_document}
)
seat_count = frappe.get_cached_value("LMS Batch", payment.payment_for_document, "seat_count")
number_of_students = frappe.db.count("LMS Batch Enrollment", {"batch": payment.payment_for_document})
if seat_count <= number_of_students:
return True
@@ -72,9 +68,7 @@ def is_batch_sold_out(payment):
def send_mail(payment):
subject = _("Complete Your Enrollment - Don't miss out!")
template = "payment_reminder"
custom_template = frappe.db.get_single_value(
"LMS Settings", "payment_reminder_template"
)
custom_template = frappe.db.get_single_value("LMS Settings", "payment_reminder_template")
args = {
"billing_name": payment.billing_name,

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record depdendencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role
@@ -71,9 +72,7 @@ def validate_possible_answer(question):
def update_question_title(question):
if not question.is_new():
question_rows = frappe.get_all(
"LMS Quiz Question", {"question": question.name}, pluck="name"
)
question_rows = frappe.get_all("LMS Quiz Question", {"question": question.name}, pluck="name")
for row in question_rows:
frappe.db.set_value("LMS Quiz Question", row, "question_detail", question.question)

View File

@@ -2,19 +2,21 @@
# For license information, please see license.txt
import json
import frappe
import re
from binascii import Error as BinasciiError
import frappe
from frappe import _, safe_decode
from frappe.core.doctype.file.utils import get_random_filename
from frappe.model.document import Document
from frappe.utils import cstr, comma_and, cint
from frappe.utils import cint, comma_and, cstr
from frappe.utils.file_manager import safe_b64decode
from fuzzywuzzy import fuzz
from lms.lms.doctype.course_lesson.course_lesson import save_progress
from lms.lms.utils import (
generate_slug,
)
from binascii import Error as BinasciiError
from frappe.utils.file_manager import safe_b64decode
from frappe.core.doctype.file.utils import get_random_filename
class LMSQuiz(Document):
@@ -28,15 +30,11 @@ class LMSQuiz(Document):
questions = [row.question for row in self.questions]
rows = [i + 1 for i, x in enumerate(questions) if questions.count(x) > 1]
if len(rows):
frappe.throw(
_("Rows {0} have the duplicate questions.").format(frappe.bold(comma_and(rows)))
)
frappe.throw(_("Rows {0} have the duplicate questions.").format(frappe.bold(comma_and(rows))))
def validate_limit(self):
if self.limit_questions_to and cint(self.limit_questions_to) >= len(self.questions):
frappe.throw(
_("Limit cannot be greater than or equal to the number of questions in the quiz.")
)
frappe.throw(_("Limit cannot be greater than or equal to the number of questions in the quiz."))
if self.limit_questions_to and cint(self.limit_questions_to) < len(self.questions):
marks = [question.marks for question in self.questions]
@@ -126,9 +124,7 @@ def quiz_summary(quiz, results):
score_out_of = quiz_details.total_marks
percentage = (score / score_out_of) * 100 if score_out_of else 0
submission = create_submission(
quiz, results, score_out_of, quiz_details.passing_percentage
)
submission = create_submission(quiz, results, score_out_of, quiz_details.passing_percentage)
save_progress_after_quiz(quiz_details, percentage)
@@ -252,11 +248,7 @@ def create_submission(quiz, results, score_out_of, passing_percentage):
def save_progress_after_quiz(quiz_details, percentage):
if (
percentage >= quiz_details.passing_percentage
and quiz_details.lesson
and quiz_details.course
):
if percentage >= quiz_details.passing_percentage and quiz_details.lesson and quiz_details.course:
save_progress(quiz_details.lesson, quiz_details.course)
elif not quiz_details.passing_percentage:
save_progress(quiz_details.lesson, quiz_details.course)

View File

@@ -10,9 +10,9 @@ import frappe
class TestLMSQuiz(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
frappe.get_doc(
{"doctype": "LMS Quiz", "title": "Test Quiz", "passing_percentage": 90}
).save(ignore_permissions=True)
frappe.get_doc({"doctype": "LMS Quiz", "title": "Test Quiz", "passing_percentage": 90}).save(
ignore_permissions=True
)
def test_with_multiple_options(self):
question = frappe.new_doc("LMS Question")

View File

@@ -2,10 +2,10 @@
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
from frappe.utils import cint
from frappe import _
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
from frappe.model.document import Document
from frappe.utils import cint
class LMSQuizSubmission(Document):

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -4,7 +4,6 @@
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list

View File

@@ -120,6 +120,4 @@ def sanitize_html(html, macro):
if macro == "YouTubeVideo":
classname = "lesson-video"
return (
"<div class='" + classname + "'>" + "\n".join(str(node) for node in nodes) + "</div>"
)
return "<div class='" + classname + "'>" + "\n".join(str(node) for node in nodes) + "</div>"

View File

@@ -1,6 +1,7 @@
import unittest
import frappe
from .utils import slugify
@@ -13,6 +14,4 @@ class TestUtils(unittest.TestCase):
def test_duplicates(self):
self.assertEqual(slugify("Hello World", ["hello-world"]), "hello-world-2")
self.assertEqual(
slugify("Hello World", ["hello-world", "hello-world-2"]), "hello-world-3"
)
self.assertEqual(slugify("Hello World", ["hello-world", "hello-world-2"]), "hello-world-3")

View File

@@ -1,9 +1,9 @@
import frappe
from frappe import _
from frappe.model.naming import append_number_if_name_exists
from frappe.website.utils import cleanup_page_name
from frappe.website.utils import is_signup_disabled
from frappe.utils import random_string, escape_html
from frappe.utils import escape_html, random_string
from frappe.website.utils import cleanup_page_name, is_signup_disabled
from lms.lms.utils import get_country_code
@@ -79,8 +79,8 @@ def set_country_from_ip(login_manager=None, user=None):
if not user and login_manager:
user = login_manager.user
user_country = frappe.db.get_value("User", user, "country")
# if user_country:
# return
if user_country:
return
frappe.db.set_value("User", user, "country", get_country_code())
return

View File

@@ -1,8 +1,9 @@
import re
import string
import frappe
import hashlib
import json
import re
import string
import frappe
import razorpay
import requests
from frappe import _
@@ -11,21 +12,22 @@ from frappe.desk.doctype.notification_log.notification_log import make_notificat
from frappe.desk.notifications import extract_mentions
from frappe.utils import (
add_months,
ceil,
cint,
cstr,
ceil,
flt,
fmt_money,
format_date,
get_datetime,
getdate,
get_fullname,
pretty_date,
get_time_str,
nowtime,
format_datetime,
get_datetime,
get_fullname,
get_time_str,
getdate,
nowtime,
pretty_date,
)
from frappe.utils.dateutils import get_period
from lms.lms.md import find_macros, markdown_to_html
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
@@ -39,9 +41,9 @@ def slugify(title, used_slugs=None):
>>> slugify("Hello World!")
'hello-world'
>>> slugify("Hello World!", ['hello-world'])
>>> slugify("Hello World!", ["hello-world"])
'hello-world-2'
>>> slugify("Hello World!", ['hello-world', 'hello-world-2'])
>>> slugify("Hello World!", ["hello-world", "hello-world-2"])
'hello-world-3'
"""
if not used_slugs:
@@ -96,9 +98,7 @@ def get_chapters(course):
"""Returns all chapters of this course."""
if not course:
return []
chapters = frappe.get_all(
"Chapter Reference", {"parent": course}, ["idx", "chapter"], order_by="idx"
)
chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["idx", "chapter"], order_by="idx")
for chapter in chapters:
chapter_details = frappe.db.get_value(
"Course Chapter",
@@ -285,9 +285,7 @@ def get_sorted_reviews(course):
def is_certified(course):
certificate = frappe.get_all(
"LMS Certificate", {"member": frappe.session.user, "course": course}
)
certificate = frappe.get_all("LMS Certificate", {"member": frappe.session.user, "course": course})
if len(certificate):
return certificate[0].name
return
@@ -295,15 +293,11 @@ def is_certified(course):
def get_lesson_index(lesson_name):
"""Returns the {chapter_index}.{lesson_index} for the lesson."""
lesson = frappe.db.get_value(
"Lesson Reference", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True
)
lesson = frappe.db.get_value("Lesson Reference", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True)
if not lesson:
return "1-1"
chapter = frappe.db.get_value(
"Chapter Reference", {"chapter": lesson.parent}, ["idx"], as_dict=True
)
chapter = frappe.db.get_value("Chapter Reference", {"chapter": lesson.parent}, ["idx"], as_dict=True)
if not chapter:
return "1-1"
@@ -358,9 +352,7 @@ def is_mentor(course, email):
"""Checks if given user is a mentor for this course."""
if not email:
return False
return frappe.db.count(
"LMS Course Mentor Mapping", {"course": course, "mentor": email}
)
return frappe.db.count("LMS Course Mentor Mapping", {"course": course, "mentor": email})
def is_cohort_staff(course, user_email):
@@ -375,9 +367,7 @@ def get_mentors(course):
course_mentors = []
mentors = frappe.get_all("LMS Course Mentor Mapping", {"course": course}, ["mentor"])
for mentor in mentors:
member = frappe.db.get_value(
"User", mentor.mentor, ["name", "username", "full_name", "user_image"]
)
member = frappe.db.get_value("User", mentor.mentor, ["name", "username", "full_name", "user_image"])
member.batch_count = frappe.db.count(
"LMS Enrollment", {"member": member.name, "member_type": "Mentor"}
)
@@ -387,9 +377,7 @@ def get_mentors(course):
def is_eligible_to_review(course):
"""Checks if user is eligible to review the course"""
if frappe.db.count(
"LMS Course Review", {"course": course, "owner": frappe.session.user}
):
if frappe.db.count("LMS Course Review", {"course": course, "owner": frappe.session.user}):
return False
return True
@@ -434,7 +422,6 @@ def convert_number_to_character(number):
def get_signup_optin_checks():
mapper = frappe._dict(
{
"terms_of_use": {"page_name": "terms_page", "title": _("Terms of Use")},
@@ -470,15 +457,11 @@ def format_number(number):
def first_lesson_exists(course):
first_chapter = frappe.db.get_value(
"Chapter Reference", {"parent": course, "idx": 1}, "name"
)
first_chapter = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": 1}, "name")
if not first_chapter:
return False
first_lesson = frappe.db.get_value(
"Lesson Reference", {"parent": first_chapter, "idx": 1}, "name"
)
first_lesson = frappe.db.get_value("Lesson Reference", {"parent": first_chapter, "idx": 1}, "name")
if not first_lesson:
return False
@@ -594,17 +577,13 @@ def create_notification_log(doc, topic):
if topic.reference_doctype == "Course Lesson":
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
course_title = frappe.db.get_value("LMS Course", course, "title")
instructors = frappe.db.get_all(
"Course Instructor", {"parent": course}, pluck="instructor"
)
instructors = frappe.db.get_all("Course Instructor", {"parent": course}, pluck="instructor")
if doc.owner != topic.owner:
users.append(topic.owner)
users += instructors
subject = _("New reply on the topic {0} in course {1}").format(
topic.title, course_title
)
subject = _("New reply on the topic {0} in course {1}").format(topic.title, course_title)
link = get_lesson_url(course, get_lesson_index(topic.reference_docname))
else:
@@ -639,15 +618,11 @@ def notify_mentions_on_portal(doc, topic):
if topic.reference_doctype == "Course Lesson":
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
subject = _("{0} mentioned you in a comment in {1}").format(
from_user_name, topic.title
)
subject = _("{0} mentioned you in a comment in {1}").format(from_user_name, topic.title)
link = get_lesson_url(course, get_lesson_index(topic.reference_docname))
else:
batch_title = frappe.db.get_value("LMS Batch", topic.reference_docname, "title")
subject = _("{0} mentioned you in a comment in {1}").format(
from_user_name, batch_title
)
subject = _("{0} mentioned you in a comment in {1}").format(from_user_name, batch_title)
link = f"/batches/{topic.reference_docname}"
for user in mentions:
@@ -736,7 +711,6 @@ def get_filtered_membership(course, memberships):
def show_start_learing_cta(course, membership):
if course.disable_self_learning or course.upcoming:
return False
if is_instructor(course.name):
@@ -756,9 +730,7 @@ def has_lessons(course):
)
if chapter_exists:
lesson_exists = frappe.db.exists(
"Lesson Reference", {"parent": chapter_exists.chapter}
)
lesson_exists = frappe.db.exists("Lesson Reference", {"parent": chapter_exists.chapter})
return lesson_exists
@@ -825,9 +797,7 @@ def get_telemetry_boot_info():
POSTHOG_PROJECT_FIELD = "posthog_project_id"
POSTHOG_HOST_FIELD = "posthog_host"
if not frappe.conf.get(POSTHOG_HOST_FIELD) or not frappe.conf.get(
POSTHOG_PROJECT_FIELD
):
if not frappe.conf.get(POSTHOG_HOST_FIELD) or not frappe.conf.get(POSTHOG_PROJECT_FIELD):
return {}
return {
@@ -1038,9 +1008,7 @@ def update_course_filters(filters):
del filters["title"]
if filters.get("enrolled"):
enrolled_courses = frappe.get_all(
"LMS Enrollment", {"member": frappe.session.user}, pluck="course"
)
enrolled_courses = frappe.get_all("LMS Enrollment", {"member": frappe.session.user}, pluck="course")
filters.update({"name": ["in", enrolled_courses]})
del filters["enrolled"]
@@ -1160,9 +1128,7 @@ def get_course_details(course):
"""course_details.course_price, course_details.currency = check_multicurrency(
course_details.course_price, course_details.currency, None, course_details.amount_usd
)"""
course_details.price = fmt_money(
course_details.course_price, 0, course_details.currency
)
course_details.price = fmt_money(course_details.course_price, 0, course_details.currency)
if frappe.session.user == "Guest":
course_details.membership = None
@@ -1176,9 +1142,7 @@ def get_course_details(course):
)
if course_details.membership and course_details.membership.current_lesson:
course_details.current_lesson = get_lesson_index(
course_details.membership.current_lesson
)
course_details.current_lesson = get_lesson_index(course_details.membership.current_lesson)
return course_details
@@ -1194,11 +1158,7 @@ def get_categorized_courses(courses):
elif course.published:
live.append(course)
if (
course.published
and not course.upcoming
and course.published_on > add_months(getdate(), -3)
):
if course.published and not course.upcoming and course.published_on > add_months(getdate(), -3):
new.append(course)
if course.membership:
@@ -1226,9 +1186,7 @@ def get_categorized_courses(courses):
def get_course_outline(course, progress=False):
"""Returns the course outline."""
outline = []
chapters = frappe.get_all(
"Chapter Reference", {"parent": course}, ["chapter", "idx"], order_by="idx"
)
chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["chapter", "idx"], order_by="idx")
for chapter in chapters:
chapter_details = frappe.db.get_value(
"Course Chapter",
@@ -1253,12 +1211,8 @@ def get_course_outline(course, progress=False):
@frappe.whitelist(allow_guest=True)
def get_lesson(course, chapter, lesson):
chapter_name = frappe.db.get_value(
"Chapter Reference", {"parent": course, "idx": chapter}, "chapter"
)
lesson_name = frappe.db.get_value(
"Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson"
)
chapter_name = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": chapter}, "chapter")
lesson_name = frappe.db.get_value("Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson")
lesson_details = frappe.db.get_value(
"Course Lesson",
lesson_name,
@@ -1315,9 +1269,7 @@ def get_lesson(course, chapter, lesson):
else:
progress = get_progress(course, lesson_details.name)
lesson_details.chapter_title = frappe.db.get_value(
"Course Chapter", chapter_name, "title"
)
lesson_details.chapter_title = frappe.db.get_value("Course Chapter", chapter_name, "title")
lesson_details.rendered_content = render_html(lesson_details)
neighbours = get_neighbour_lesson(course, chapter, lesson)
lesson_details.next = neighbours["next"]
@@ -1363,9 +1315,7 @@ def get_neighbour_lesson(course, chapter, lesson):
@frappe.whitelist(allow_guest=True)
def get_batch_details(batch):
batch_students = frappe.get_all(
"LMS Batch Enrollment", {"batch": batch}, pluck="member"
)
batch_students = frappe.get_all("LMS Batch Enrollment", {"batch": batch}, pluck="member")
if (
not frappe.db.get_value("LMS Batch", batch, "published")
and has_student_role()
@@ -1437,17 +1387,13 @@ def categorize_batches(batches):
private.append(batch)
elif getdate(batch.start_date) < getdate():
archived.append(batch)
elif (
getdate(batch.start_date) == getdate() and get_time_str(batch.start_time) < nowtime()
):
elif getdate(batch.start_date) == getdate() and get_time_str(batch.start_time) < nowtime():
archived.append(batch)
else:
upcoming.append(batch)
if frappe.session.user != "Guest":
if frappe.db.exists(
"LMS Batch Enrollment", {"member": frappe.session.user, "batch": batch.name}
):
if frappe.db.exists("LMS Batch Enrollment", {"member": frappe.session.user, "batch": batch.name}):
enrolled.append(batch)
categories = [archived, private, enrolled]
@@ -1525,9 +1471,7 @@ def get_assessments(batch, member=None):
def get_assignment_details(assessment, member):
assessment.title = frappe.db.get_value(
"LMS Assignment", assessment.assessment_name, "title"
)
assessment.title = frappe.db.get_value("LMS Assignment", assessment.assessment_name, "title")
existing_submission = frappe.db.exists(
{
@@ -1552,9 +1496,7 @@ def get_assignment_details(assessment, member):
assessment.edit_url = f"/assignments/{assessment.assessment_name}"
submission_name = existing_submission if existing_submission else "new-submission"
assessment.url = (
f"/assignment-submission/{assessment.assessment_name}/{submission_name}"
)
assessment.url = f"/assignment-submission/{assessment.assessment_name}/{submission_name}"
return assessment
@@ -1585,18 +1527,14 @@ def get_quiz_details(assessment, member):
assessment.completed = False
assessment.edit_url = f"/quizzes/{assessment.assessment_name}"
submission_name = (
existing_submission[0].name if len(existing_submission) else "new-submission"
)
submission_name = existing_submission[0].name if len(existing_submission) else "new-submission"
assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}"
return assessment
def get_exercise_details(assessment, member):
assessment.title = frappe.db.get_value(
"LMS Programming Exercise", assessment.assessment_name, "title"
)
assessment.title = frappe.db.get_value("LMS Programming Exercise", assessment.assessment_name, "title")
filters = {"member": member, "exercise": assessment.assessment_name}
if frappe.db.exists("LMS Programming Exercise Submission", filters):
@@ -1657,9 +1595,7 @@ def get_batch_students(batch):
""" Iterate through assessments and track their progress """
for assessment in assessments:
title = frappe.db.get_value(
assessment.assessment_type, assessment.assessment_name, "title"
)
title = frappe.db.get_value(assessment.assessment_type, assessment.assessment_name, "title")
assessment_info = has_submitted_assessment(
assessment.assessment_name, assessment.assessment_type, student.member
)
@@ -1672,11 +1608,7 @@ def get_batch_students(batch):
detail.assessments_completed = assessments_completed
if len(batch_courses) + len(assessments):
detail.progress = flt(
(
(courses_completed + assessments_completed)
/ (len(batch_courses) + len(assessments))
* 100
),
((courses_completed + assessments_completed) / (len(batch_courses) + len(assessments)) * 100),
2,
)
else:
@@ -1712,9 +1644,7 @@ def has_submitted_assessment(assessment, assessment_type, member=None):
attempt_details = frappe.db.get_value(doctype, filters, fields, as_dict=1)
if assessment_type == "LMS Quiz":
result = "Failed"
passing_percentage = frappe.db.get_value(
"LMS Quiz", assessment, "passing_percentage"
)
passing_percentage = frappe.db.get_value("LMS Quiz", assessment, "passing_percentage")
if attempt_details.percentage >= passing_percentage:
result = "Pass"
else:
@@ -1762,9 +1692,7 @@ def get_discussion_topics(doctype, docname, single_thread):
)
for topic in topics:
topic.user = frappe.db.get_value(
"User", topic.owner, ["full_name", "user_image"], as_dict=True
)
topic.user = frappe.db.get_value("User", topic.owner, ["full_name", "user_image"], as_dict=True)
return topics
@@ -1794,9 +1722,7 @@ def get_discussion_replies(topic):
)
for reply in replies:
reply.user = frappe.db.get_value(
"User", reply.owner, ["full_name", "user_image"], as_dict=True
)
reply.user = frappe.db.get_value("User", reply.owner, ["full_name", "user_image"], as_dict=True)
return replies
@@ -1849,12 +1775,8 @@ def get_order_summary(doctype, docname, country=None):
@frappe.whitelist()
def get_lesson_creation_details(course, chapter, lesson):
chapter_name = frappe.db.get_value(
"Chapter Reference", {"parent": course, "idx": chapter}, "chapter"
)
lesson_name = frappe.db.get_value(
"Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson"
)
chapter_name = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": chapter}, "chapter")
lesson_name = frappe.db.get_value("Lesson Reference", {"parent": chapter_name, "idx": lesson}, "lesson")
if lesson_name:
lesson_details = frappe.db.get_value(
@@ -1876,9 +1798,7 @@ def get_lesson_creation_details(course, chapter, lesson):
return {
"course_title": frappe.db.get_value("LMS Course", course, "title"),
"chapter": frappe.db.get_value(
"Course Chapter", chapter_name, ["title", "name"], as_dict=True
),
"chapter": frappe.db.get_value("Course Chapter", chapter_name, ["title", "name"], as_dict=True),
"lesson": lesson_details if lesson_name else None,
}
@@ -1895,9 +1815,7 @@ def get_roles(name):
def publish_notifications(doc, method):
frappe.publish_realtime(
"publish_lms_notifications", user=doc.for_user, after_commit=True
)
frappe.publish_realtime("publish_lms_notifications", user=doc.for_user, after_commit=True)
def update_payment_record(doctype, docname):
@@ -1933,9 +1851,7 @@ def update_payment_record(doctype, docname):
"order_id": data.get("order_id"),
},
)
payment_for_certificate = frappe.db.get_value(
"LMS Payment", data.payment, "payment_for_certificate"
)
payment_for_certificate = frappe.db.get_value("LMS Payment", data.payment, "payment_for_certificate")
try:
if payment_for_certificate:
@@ -1945,17 +1861,13 @@ def update_payment_record(doctype, docname):
else:
enroll_in_batch(docname, data.payment)
except Exception as e:
frappe.log_error(frappe.get_traceback(), _("Enrollment Failed"))
frappe.log_error(frappe.get_traceback(), _("Enrollment Failed, {0}").format(e))
def enroll_in_course(course, payment_name):
if not frappe.db.exists(
"LMS Enrollment", {"member": frappe.session.user, "course": course}
):
if not frappe.db.exists("LMS Enrollment", {"member": frappe.session.user, "course": course}):
enrollment = frappe.new_doc("LMS Enrollment")
payment = frappe.db.get_value(
"LMS Payment", payment_name, ["name", "source"], as_dict=True
)
payment = frappe.db.get_value("LMS Payment", payment_name, ["name", "source"], as_dict=True)
enrollment.update(
{
@@ -1969,12 +1881,8 @@ def enroll_in_course(course, payment_name):
@frappe.whitelist()
def enroll_in_batch(batch, payment_name=None):
if not frappe.db.exists(
"LMS Batch Enrollment", {"batch": batch, "member": frappe.session.user}
):
batch_doc = frappe.db.get_value(
"LMS Batch", batch, ["name", "seat_count"], as_dict=True
)
if not frappe.db.exists("LMS Batch Enrollment", {"batch": batch, "member": frappe.session.user}):
batch_doc = frappe.db.get_value("LMS Batch", batch, ["name", "seat_count"], as_dict=True)
students = frappe.db.count("LMS Batch Enrollment", {"batch": batch})
if batch_doc.seat_count and students >= batch_doc.seat_count:
frappe.throw(_("The batch is full. Please contact the Administrator."))
@@ -1988,9 +1896,7 @@ def enroll_in_batch(batch, payment_name=None):
)
if payment_name:
payment = frappe.db.get_value(
"LMS Payment", payment_name, ["name", "source"], as_dict=True
)
payment = frappe.db.get_value("LMS Payment", payment_name, ["name", "source"], as_dict=True)
new_student.update(
{
"payment": payment.name,
@@ -2013,11 +1919,7 @@ def update_certificate_purchase(course, payment_name):
@frappe.whitelist()
def get_programs():
if (
has_course_moderator_role()
or has_course_instructor_role()
or has_course_evaluator_role()
):
if has_course_moderator_role() or has_course_instructor_role() or has_course_evaluator_role():
programs = frappe.get_all("LMS Program", fields=["name"])
else:
programs = frappe.get_all(
@@ -2049,14 +1951,10 @@ def get_programs():
@frappe.whitelist()
def enroll_in_program_course(program, course):
enrollment = frappe.db.exists(
"LMS Enrollment", {"member": frappe.session.user, "course": course}
)
enrollment = frappe.db.exists("LMS Enrollment", {"member": frappe.session.user, "course": course})
if enrollment:
enrollment = frappe.db.get_value(
"LMS Enrollment", enrollment, ["name", "current_lesson"], as_dict=1
)
enrollment = frappe.db.get_value("LMS Enrollment", enrollment, ["name", "current_lesson"], as_dict=1)
enrollment.current_lesson = get_lesson_index(enrollment.current_lesson)
return enrollment
@@ -2064,9 +1962,7 @@ def enroll_in_program_course(program, course):
"LMS Program Course", {"parent": program}, ["course", "idx"], order_by="idx"
)
current_course_idx = [
program_course.idx
for program_course in program_courses
if program_course.course == course
program_course.idx for program_course in program_courses if program_course.course == course
][0]
for program_course in program_courses:
@@ -2147,16 +2043,14 @@ def filter_batches_based_on_start_time(batches, filters):
batches_to_remove = [
batch
for batch in batches
if getdate(batch.start_date) == getdate()
and get_time_str(batch.start_time) < nowtime()
if getdate(batch.start_date) == getdate() and get_time_str(batch.start_time) < nowtime()
]
batches = [batch for batch in batches if batch not in batches_to_remove]
elif batchType == "archived":
batches_to_remove = [
batch
for batch in batches
if getdate(batch.start_date) == getdate()
and get_time_str(batch.start_time) >= nowtime()
if getdate(batch.start_date) == getdate() and get_time_str(batch.start_time) >= nowtime()
]
batches = [batch for batch in batches if batch not in batches_to_remove]
return batches
@@ -2217,9 +2111,7 @@ def get_palette(full_name):
@frappe.whitelist(allow_guest=True)
def get_related_courses(course):
related_course_details = []
related_courses = frappe.get_all(
"Related Courses", {"parent": course}, order_by="idx", pluck="course"
)
related_courses = frappe.get_all("Related Courses", {"parent": course}, order_by="idx", pluck="course")
for related_course in related_courses:
related_course_details.append(get_course_details(related_course))

View File

@@ -2,117 +2,16 @@
Handles rendering of profile pages.
"""
import re
import os
import mimetypes
import os
import frappe
from frappe.utils import get_files_path
from frappe.website.page_renderers.base_renderer import BaseRenderer
from frappe.website.page_renderers.document_page import DocumentPage
from frappe.website.page_renderers.list_page import ListPage
from frappe.website.page_renderers.not_found_page import NotFoundPage
from frappe.website.page_renderers.print_page import PrintPage
from frappe.website.page_renderers.redirect_page import RedirectPage
from frappe.website.page_renderers.static_page import StaticPage
from frappe.website.page_renderers.template_page import TemplatePage
from frappe.website.page_renderers.web_form import WebFormPage
from werkzeug.wrappers import Response
from werkzeug.wsgi import wrap_file
def get_profile_url(username):
"""Returns the profile URL given username.
The default URL prefix for profiles is /users, but tha can be customized.
This functions looks at the current value from the config and generates
the URL for the profile.
"""
return get_profile_url_prefix() + username
def get_profile_url_prefix():
hooks = frappe.get_hooks("profile_url_prefix") or ["/users/"]
return hooks[-1]
RE_INVALID_USERNAME = re.compile("[@!#$%^&*()<>?/\\|}{~:-]")
class ProfileRedirectPage(BaseRenderer):
"""Renderer to redirect /profile_/foo to <profile_prefix>/foo.
This is useful to redirect to profile pages from javascript as there is no
easy to find the profile prefix.
"""
def can_render(self):
return self.path.startswith("profile_/")
def render(self):
username = self.path[len("profile_/") :]
frappe.flags.redirect_location = get_profile_url_prefix() + username
return RedirectPage(self.path).render()
class ProfilePage(BaseRenderer):
def __init__(self, path, http_status_code):
super().__init__(path, http_status_code)
self.renderer = None
def can_render(self):
"""if "." in self.path:
return False"""
# has prefix and path starts with prefix?
prefix = get_profile_url_prefix().lstrip("/")
if prefix and not self.path.startswith(prefix):
return False
# not a userpage?
username = self.get_username()
""" if RE_INVALID_USERNAME.search(username):
return False """
# if there is prefix then we can allow all usernames
if prefix:
return True
# if we are having top-level usernames, then give preference to
# the existing website_route_rules, web pages, web forms etc.
# Don't handle any of the exsiting website_route_rules
routes = [rule["to_route"] for rule in frappe.get_hooks("website_route_rules")]
if self.path in routes:
return False
# if any of the existing renders can render, let them do
renderers = [StaticPage, WebFormPage, DocumentPage, TemplatePage, ListPage, PrintPage]
for renderer in renderers:
renderer_instance = renderer(self.path, 200)
if renderer_instance.can_render():
self.renderer = renderer_instance
return True
return True
def get_username(self):
prefix = get_profile_url_prefix().lstrip("/")
return self.path[len(prefix) :]
def render(self):
if self.renderer:
return self.renderer.render()
else:
username = self.get_username()
return render_portal_page("profiles/profile", username=username)
def render_portal_page(path, **kwargs):
frappe.form_dict.update(kwargs)
page = TemplatePage(path)
return page.render()
class SCORMRenderer(BaseRenderer):
def can_render(self):
return "scorm/" in self.path
@@ -127,9 +26,7 @@ class SCORMRenderer(BaseRenderer):
# check if path exists and is actually a file and not a folder
if os.path.exists(path) and os.path.isfile(path):
f = open(path, "rb")
response = Response(
wrap_file(frappe.local.request.environ, f), direct_passthrough=True
)
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
response.mimetype = mimetypes.guess_type(path)[0]
return response
else:
@@ -138,28 +35,22 @@ class SCORMRenderer(BaseRenderer):
index_path = os.path.join(path, "index.html")
if os.path.exists(index_path):
f = open(index_path, "rb")
response = Response(
wrap_file(frappe.local.request.environ, f), direct_passthrough=True
)
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
response.mimetype = mimetypes.guess_type(index_path)[0]
return response
elif not os.path.exists(path):
chapter_folder = "/".join(self.path.split("/")[:3])
chapter_folder_path = os.path.realpath(
frappe.get_site_path("public", chapter_folder)
)
chapter_folder_path = os.path.realpath(frappe.get_site_path("public", chapter_folder))
file = path.split("/")[-1]
correct_file_path = None
for root, dirs, files in os.walk(chapter_folder_path):
for root, _dirs, files in os.walk(chapter_folder_path):
if file in files:
correct_file_path = os.path.join(root, file)
break
if correct_file_path:
f = open(correct_file_path, "rb")
response = Response(
wrap_file(frappe.local.request.environ, f), direct_passthrough=True
)
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
response.mimetype = mimetypes.guess_type(correct_file_path)[0]
return response

View File

@@ -9,9 +9,7 @@ def execute():
base_path = frappe.get_app_path("lms", "templates", "emails")
if not frappe.db.exists("Email Template", _("Mentor Request Creation Template")):
response = frappe.read_file(
os.path.join(base_path, "mentor_request_creation_email.html")
)
response = frappe.read_file(os.path.join(base_path, "mentor_request_creation_email.html"))
frappe.get_doc(
{
"doctype": "Email Template",
@@ -29,9 +27,7 @@ def execute():
)
if not frappe.db.exists("Email Template", _("Mentor Request Status Update Template")):
response = frappe.read_file(
os.path.join(base_path, "mentor_request_status_update_email.html")
)
response = frappe.read_file(os.path.join(base_path, "mentor_request_status_update_email.html"))
frappe.get_doc(
{
"doctype": "Email Template",

View File

@@ -5,8 +5,6 @@ def execute():
frappe.reload_doc("lms", "doctype", "lms_message")
messages = frappe.get_all("LMS Message", ["author", "name"])
for message in messages:
user = frappe.db.get_value(
"Community Member", message.author, ["email", "full_name"], as_dict=True
)
user = frappe.db.get_value("Community Member", message.author, ["email", "full_name"], as_dict=True)
frappe.db.set_value("LMS Message", message.name, "author", user.email)
frappe.db.set_value("LMS Message", message.name, "author_name", user.full_name)

View File

@@ -5,8 +5,6 @@ def execute():
frappe.reload_doc("lms", "doctype", "lms_mentor_request")
requests = frappe.get_all("LMS Mentor Request", ["member", "name"])
for request in requests:
user = frappe.db.get_value(
"Community Member", request.member, ["email", "full_name"], as_dict=True
)
user = frappe.db.get_value("Community Member", request.member, ["email", "full_name"], as_dict=True)
frappe.db.set_value("LMS Mentor Request", request.name, "member", user.email)
frappe.db.set_value("LMS Mentor Request", request.name, "member_name", user.full_name)

View File

@@ -6,6 +6,4 @@ def execute():
members = frappe.get_all("Community Member", ["name", "email_preference"])
for member in members:
if not member.email_preference:
frappe.db.set_value(
"Community Member", member.name, "email_preference", "Email on every Message"
)
frappe.db.set_value("Community Member", member.name, "email_preference", "Email on every Message")

View File

@@ -1,4 +1,5 @@
import frappe
from lms.install import add_pages_to_nav

View File

@@ -6,9 +6,7 @@ from lms.lms.utils import get_course_progress
def execute():
frappe.reload_doc("lms", "doctype", "lms_batch_membership")
memberships = frappe.get_all(
"LMS Enrollment", ["name", "course", "member"], order_by="course"
)
memberships = frappe.get_all("LMS Enrollment", ["name", "course", "member"], order_by="course")
if len(memberships):
current_course = memberships[0].course

View File

@@ -30,8 +30,6 @@ def amend_course_description():
courses = frappe.get_all("LMS Course", fields=["name", "description"])
for course in courses:
frappe.db.set_value(
"LMS Course", course.name, "description", to_markdown(course.description)
)
frappe.db.set_value("LMS Course", course.name, "description", to_markdown(course.description))
frappe.reload_doc("lms", "doctype", "lms_course")

View File

@@ -2,9 +2,7 @@ import frappe
def execute():
assignment_lessons = frappe.get_all(
"Course Lesson", {"file_type": ["is", "set"]}, ["name", "question"]
)
assignment_lessons = frappe.get_all("Course Lesson", {"file_type": ["is", "set"]}, ["name", "question"])
for lesson in assignment_lessons:
if not lesson.question:

View File

@@ -5,6 +5,4 @@ def execute():
frappe.reload_doc("lms", "doctype", "lms_certification")
certificates = frappe.get_all("LMS Certification", fields=["name", "student"])
for certificate in certificates:
frappe.db.set_value(
"LMS Certification", certificate.name, "member", certificate.student
)
frappe.db.set_value("LMS Certification", certificate.name, "member", certificate.student)

View File

@@ -4,6 +4,4 @@ import frappe
def execute():
value = frappe.db.get_single_value("LMS Settings", "portal_course_creation")
if value == "Course Instructor Role":
frappe.db.set_value(
"LMS Settings", None, "portal_course_creation", "Course Creator Role"
)
frappe.db.set_value("LMS Settings", None, "portal_course_creation", "Course Creator Role")

View File

@@ -1,4 +1,5 @@
import frappe
from lms.lms.md import markdown_to_html

View File

@@ -1,4 +1,5 @@
import frappe
from lms.lms.md import markdown_to_html

View File

@@ -6,6 +6,4 @@ def execute():
frappe.reload_doc("lms", "doctype", "lms_course_progress")
progress_records = frappe.get_all("LMS Enrollment", fields=["name", "progress"])
for progress in progress_records:
frappe.db.set_value(
"LMS Enrollment", progress.name, "progress", flt(progress.progress)
)
frappe.db.set_value("LMS Enrollment", progress.name, "progress", flt(progress.progress))

View File

@@ -1,4 +1,5 @@
import frappe
from lms.install import create_course_creator_role

View File

@@ -2,7 +2,6 @@ import frappe
def execute():
frappe.db.delete("DocType", {"module": "Conference"})
frappe.db.delete("DocType", {"module": "Hackathon"})
frappe.db.delete("DocType", {"module": "Event Management"})

View File

@@ -3,7 +3,6 @@ from frappe.installer import add_to_installed_apps, remove_from_installed_apps
def execute():
if "community" in frappe.db.get_global("installed_apps"):
remove_from_installed_apps("community")
add_to_installed_apps("school")

View File

@@ -6,6 +6,4 @@ def execute():
submissions = frappe.db.get_all("LMS Quiz Submission", fields=["name", "owner"])
for submission in submissions:
frappe.db.set_value(
"LMS Quiz Submission", submission.name, "member", submission.owner
)
frappe.db.set_value("LMS Quiz Submission", submission.name, "member", submission.owner)

View File

@@ -49,6 +49,4 @@ def move_lessons():
def change_parent_for_lesson_reference():
lesson_reference = frappe.get_all("Lesson Reference", fields=["name", "parent"])
for reference in lesson_reference:
frappe.db.set_value(
"Lesson Reference", reference.name, "parenttype", "Course Chapter"
)
frappe.db.set_value("Lesson Reference", reference.name, "parenttype", "Course Chapter")

View File

@@ -3,7 +3,6 @@ from frappe.installer import add_to_installed_apps, remove_from_installed_apps
def execute():
if "school" in frappe.db.get_global("installed_apps"):
remove_from_installed_apps("school")
add_to_installed_apps("lms")

View File

@@ -3,9 +3,7 @@ import frappe
def execute():
frappe.reload_doc("lms", "doctype", "lms_course_progress")
progress_records = frappe.get_all(
"LMS Course Progress", fields=["name", "owner", "member"]
)
progress_records = frappe.get_all("LMS Course Progress", fields=["name", "owner", "member"])
for progress in progress_records:
if not progress.member:

View File

@@ -3,9 +3,7 @@ import frappe
def execute():
frappe.reload_doc("lms", "doctype", "lms_course")
courses = frappe.get_all(
"LMS Course", {"status": ("is", "not set")}, ["name", "published"]
)
courses = frappe.get_all("LMS Course", {"status": ("is", "not set")}, ["name", "published"])
for course in courses:
status = "Approved" if course.published else "In Progress"
frappe.db.set_value("LMS Course", course.name, "status", status)

View File

@@ -2,9 +2,7 @@ import frappe
def execute():
courses = frappe.get_all(
"LMS Course", {"video_link": ["is", "set"]}, ["name", "video_link"]
)
courses = frappe.get_all("LMS Course", {"video_link": ["is", "set"]}, ["name", "video_link"])
for course in courses:
if course.video_link:
link = course.video_link.split("/")[-1]

View File

@@ -15,6 +15,4 @@ def execute():
if frappe.db.exists("Print Format", default_certificate_template):
certificates = frappe.get_all("LMS Certificate", pluck="name")
for certificate in certificates:
frappe.db.set_value(
"LMS Certificate", certificate, "template", default_certificate_template
)
frappe.db.set_value("LMS Certificate", certificate, "template", default_certificate_template)

View File

@@ -13,6 +13,4 @@ def execute():
for quiz in quizzes:
questions_count = frappe.db.count("LMS Quiz Question", {"parent": quiz})
frappe.db.set_value(
"LMS Quiz", quiz, {"total_marks": questions_count, "passing_percentage": 100}
)
frappe.db.set_value("LMS Quiz", quiz, {"total_marks": questions_count, "passing_percentage": 100})

View File

@@ -1,4 +1,5 @@
import frappe
from lms.install import create_batch_source

View File

@@ -5,14 +5,10 @@ def execute():
frappe.reload_doc("lms", "doctype", "class_student")
frappe.reload_doc("lms", "doctype", "class_student_registration")
students = frappe.get_all(
"Class Student", {"parent": ["is", "set"]}, ["name", "student", "parent"]
)
students = frappe.get_all("Class Student", {"parent": ["is", "set"]}, ["name", "student", "parent"])
for student in students:
student_details = frappe.db.get_value(
"User", student.student, ["full_name", "username"], as_dict=1
)
student_details = frappe.db.get_value("User", student.student, ["full_name", "username"], as_dict=1)
registration = frappe.new_doc("Class Student Registration")
registration.member = student.student
registration.member_name = student_details.full_name

View File

@@ -1,13 +1,12 @@
import frappe
from lms.install import create_lms_student_role
def execute():
create_lms_student_role()
users = frappe.get_all(
"User", filters={"user_type": "Website User", "enabled": 1}, pluck="name"
)
users = frappe.get_all("User", filters={"user_type": "Website User", "enabled": 1}, pluck="name")
for user in users:
filters = {

View File

@@ -2,7 +2,5 @@ import frappe
def execute():
if frappe.db.exists("Role", "Class Evaluator") and not frappe.db.exists(
"Role", "Batch Evaluator"
):
if frappe.db.exists("Role", "Class Evaluator") and not frappe.db.exists("Role", "Batch Evaluator"):
frappe.rename_doc("Role", "Class Evaluator", "Batch Evaluator")

View File

@@ -2,9 +2,7 @@ import frappe
def execute():
courses = frappe.get_all(
"LMS Course", filters={"published": 1}, fields=["name", "creation"]
)
courses = frappe.get_all("LMS Course", filters={"published": 1}, fields=["name", "creation"])
for course in courses:
frappe.db.set_value("LMS Course", course.name, "published_on", course.creation)

View File

@@ -1,4 +1,5 @@
import frappe
from lms.lms.api import update_course_statistics

View File

@@ -3,8 +3,6 @@ from frappe.utils import ceil, flt
def execute():
quizzes = frappe.get_all(
"LMS Quiz", fields=["name", "duration"], filters={"duration": [">", 0]}
)
quizzes = frappe.get_all("LMS Quiz", fields=["name", "duration"], filters={"duration": [">", 0]})
for quiz in quizzes:
frappe.db.set_value("LMS Quiz", quiz.name, "duration", ceil(flt(quiz.duration) / 60))

View File

@@ -3,9 +3,7 @@ import frappe
def execute():
if "payments" not in frappe.get_installed_apps():
web_form_custom_fields = frappe.get_all(
"Custom Field", {"dt": "Web Form"}, ["name", "fieldname"]
)
web_form_custom_fields = frappe.get_all("Custom Field", {"dt": "Web Form"}, ["name", "fieldname"])
unused_fields = [
"currency",

View File

@@ -1,4 +1,5 @@
import frappe
from lms.lms.utils import get_course_progress

View File

@@ -1,4 +1,5 @@
import frappe
from lms.lms.api import give_discussions_permission

View File

@@ -16,9 +16,7 @@ def execute():
)
for student in students:
if not frappe.db.exists(
"LMS Batch Enrollment", {"member": student.student, "batch": student.parent}
):
if not frappe.db.exists("LMS Batch Enrollment", {"member": student.student, "batch": student.parent}):
doc = frappe.new_doc("LMS Batch Enrollment")
doc.member = student.student
doc.member_name = student.student_name

View File

@@ -2,9 +2,7 @@ import frappe
def execute():
show_certified_members = frappe.db.get_single_value(
"LMS Settings", "certified_participants"
)
show_certified_members = frappe.db.get_single_value("LMS Settings", "certified_participants")
if show_certified_members:
frappe.db.set_single_value("LMS Settings", "certified_members", 1)

View File

@@ -9,6 +9,4 @@ def execute():
if evaluation.date > getdate():
frappe.db.set_value("LMS Certificate Request", evaluation.name, "status", "Upcoming")
else:
frappe.db.set_value(
"LMS Certificate Request", evaluation.name, "status", "Completed"
)
frappe.db.set_value("LMS Certificate Request", evaluation.name, "status", "Completed")

View File

@@ -10,9 +10,7 @@ def set_question_data():
questions = frappe.get_all("LMS Quiz Question", fields=["name", "question"])
for question in questions:
question_doc = frappe.db.get_value(
"LMS Question", question.question, ["question", "type"], as_dict=1
)
question_doc = frappe.db.get_value("LMS Question", question.question, ["question", "type"], as_dict=1)
frappe.db.set_value(
"LMS Quiz Question",
question.name,

View File

@@ -14,8 +14,9 @@ The PageExtension is used to load additinal stylesheets and scripts to
be loaded in a webpage.
"""
import frappe
from urllib.parse import quote
import frappe
from frappe import _
@@ -131,9 +132,7 @@ def quiz_renderer(quiz_name):
details["marks"] = question.marks
quiz.questions.append(details)
no_of_attempts = frappe.db.count(
"LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name}
)
no_of_attempts = frappe.db.count("LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name})
if quiz.show_submission_history:
all_submissions = frappe.get_all(

View File

@@ -1,5 +1,4 @@
"""Utilities for making custom routing.
"""
"""Utilities for making custom routing."""
from werkzeug.datastructures import ImmutableDict
from werkzeug.routing import BaseConverter, Map

View File

@@ -7,6 +7,7 @@ them will be a lot easier.
The widgets will be provided
"""
import frappe
from frappe.utils.jinja import get_jenv

View File

@@ -1,12 +1,11 @@
import frappe
from urllib.parse import quote
import frappe
def get_context(context):
context.no_cache = 1
template = frappe.db.get_value(
"LMS Certificate", frappe.form_dict.certificate_id, "template"
)
template = frappe.db.get_value("LMS Certificate", frappe.form_dict.certificate_id, "template")
certificate_id = frappe.form_dict.certificate_id
template = quote(template)

View File

@@ -1,5 +1,6 @@
import frappe
import re
import frappe
from bs4 import BeautifulSoup
from frappe import _
from frappe.utils.telemetry import capture
@@ -13,10 +14,7 @@ def get_context():
frappe.db.commit()
app_path = frappe.form_dict.get("app_path")
favicon = (
frappe.db.get_single_value("Website Settings", "favicon")
or "/assets/lms/frontend/favicon.png"
)
favicon = frappe.db.get_single_value("Website Settings", "favicon") or "/assets/lms/frontend/favicon.png"
title = frappe.db.get_single_value("Website Settings", "app_name") or "Frappe Learning"
context.meta = get_meta(app_path, title, favicon)

View File

@@ -29,3 +29,38 @@ force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
indent = "\t"
[tool.ruff]
line-length = 110
target-version = "py310"
[tool.ruff.lint]
select = [
"F",
"E",
"W",
"I",
"UP",
"B",
]
ignore = [
"B017", # assertRaises(Exception) - should be more specific
"B018", # useless expression, not assigned to anything
"B023", # function doesn't bind loop variable - will have last iteration's value
"B904", # raise inside except without from
"E101", # indentation contains mixed spaces and tabs
"E402", # module level import not at top of file
"E501", # line too long
"E741", # ambiguous variable name
"F401", # "unused" imports
"F403", # can't detect undefined names from * import
"F405", # can't detect undefined names from * import
"F722", # syntax error in forward type annotation
"F821", # undefined name
"W191", # indentation contains tabs
]
[tool.ruff.format]
quote-style = "double"
indent-style = "tab"
docstring-code-format = true