Merge remote-tracking branch 'upstream/develop' into fix/course-deletion

This commit is contained in:
raizasafeel
2026-01-22 16:33:07 +05:30
91 changed files with 11278 additions and 8036 deletions
+45 -1
View File
@@ -1,3 +1,5 @@
import json
import frappe
ALLOWED_PATHS = [
@@ -12,6 +14,15 @@ ALLOWED_PATHS = [
"/api/method/frappe.integrations.oauth2.authorize",
"/api/method/frappe.integrations.oauth2.approve",
"/api/method/frappe.integrations.oauth2.get_token",
"/api/method/frappe.www.login.login_via_google",
"/api/method/frappe.www.login.login_via_github",
"/api/method/frappe.www.login.login_via_facebook",
"/api/method/frappe.www.login.login_via_frappe",
"/api/method/frappe.www.login.login_via_office365",
"/api/method/frappe.www.login.login_via_salesforce",
"/api/method/frappe.www.login.login_via_fairlogin",
"/api/method/frappe.www.login.login_via_keycloak",
"/api/method/frappe.www.login.custom",
"/api/method/frappe.integrations.oauth2.openid_profile",
"/api/method/frappe.website.doctype.web_page_view.web_page_view.make_view_log",
"/api/method/upload_file",
@@ -33,10 +44,14 @@ ALLOWED_PATHS = [
"/api/method/frappe.utils.print_format.download_pdf",
"/api/method/frappe.desk.search.search_link",
"/api/method/frappe.core.doctype.communication.email.make",
"/api/method/frappe.core.doctype.user.user.reset_password",
]
def authenticate():
if not frappe.conf.get("block_endpoints"):
return
if frappe.form_dict.cmd:
path = f"/api/method/{frappe.form_dict.cmd}"
else:
@@ -48,10 +63,39 @@ def authenticate():
if not path.startswith("/api/"):
return
print("path", path)
if path.startswith("/lms") or path.startswith("/api/method/lms."):
return
if is_server_script_path(path):
return
if is_custom_app_endpoint(path):
return
if path in ALLOWED_PATHS:
return
frappe.throw(f"Access not allowed for this URL: {path}", frappe.PermissionError)
def is_server_script_path(path):
endpoint = path.split("/api/method/")[-1]
if frappe.db.exists("Server Script", {"script_type": "API", "api_method": endpoint, "disabled": 0}):
return True
return False
def is_custom_app_endpoint(path):
allowed_custom_endpoints = frappe.conf.get("allowed_custom_endpoints", [])
if isinstance(allowed_custom_endpoints, str):
try:
parsed = json.loads(allowed_custom_endpoints)
allowed_custom_endpoints = parsed if isinstance(parsed, list) else [allowed_custom_endpoints]
except Exception:
allowed_custom_endpoints = [allowed_custom_endpoints]
for endpoint in allowed_custom_endpoints:
if endpoint in path:
return True
return False
+2 -2
View File
@@ -257,12 +257,12 @@
"length": 0,
"link_filters": null,
"mandatory_depends_on": null,
"modified": "2025-12-24 12:56:32.110405",
"modified": "2025-12-24 12:56:32.110406",
"module": null,
"name": "User-open_to",
"no_copy": 0,
"non_negative": 0,
"options": "\nOpportunities\nHiring",
"options": "\nWork\nHiring",
"permlevel": 0,
"precision": "",
"print_hide": 0,
+2 -2
View File
@@ -331,8 +331,8 @@ def get_certification_query(filters):
)
if field == "member_name":
query = query.where(Certificate.member_name.like(value[1]))
if field == "open_to_opportunities":
query = query.where(User.open_to == "Opportunities")
if field == "open_to_work":
query = query.where(User.open_to == "Work")
if field == "hiring":
query = query.where(User.open_to == "Hiring")
return query
-8
View File
@@ -3,14 +3,6 @@
frappe.ui.form.on("LMS Batch", {
onload: function (frm) {
frm.set_query("student", "students", function (doc) {
return {
filters: {
ignore_user_type: 1,
},
};
});
frm.set_query("reference_doctype", "timetable", function () {
let doctypes = ["Course Lesson", "LMS Quiz", "LMS Assignment"];
return {
+1 -1
View File
@@ -37,7 +37,7 @@ class LMSBatch(Document):
def on_update(self):
if self.has_value_changed("published") and self.published:
frappe.enqueue(send_notification_for_published_batch, batch=self, now=True)
frappe.enqueue(send_notification_for_published_batch, batch=self)
def autoname(self):
if not self.name:
+7 -7
View File
@@ -166,14 +166,14 @@ class TestLMSUtils(BaseTestUtils):
certified_participants_no_match = get_certified_participants(filters=filters)
self.assertEqual(len(certified_participants_no_match), 0)
def test_certified_participants_with_open_to_opportunities(self):
filters = {"open_to_opportunities": 1}
certified_participants_open_to_oppo = get_certified_participants(filters=filters)
self.assertEqual(len(certified_participants_open_to_oppo), 0)
def test_certified_participants_with_open_to_work(self):
filters = {"open_to_work": 1}
certified_participants_open_to_work = get_certified_participants(filters=filters)
self.assertEqual(len(certified_participants_open_to_work), 0)
frappe.db.set_value("User", self.student1.email, "open_to", "Opportunities")
certified_participants_open_to_oppo = get_certified_participants(filters=filters)
self.assertEqual(len(certified_participants_open_to_oppo), 1)
frappe.db.set_value("User", self.student1.email, "open_to", "Work")
certified_participants_open_to_work = get_certified_participants(filters=filters)
self.assertEqual(len(certified_participants_open_to_work), 1)
frappe.db.set_value("User", self.student1.email, "open_to", "")
def test_certified_participants_with_open_to_hiring(self):
+468 -353
View File
File diff suppressed because it is too large Load Diff
+386 -271
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+380 -265
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+395 -280
View File
File diff suppressed because it is too large Load Diff
+394 -279
View File
File diff suppressed because it is too large Load Diff
+392 -277
View File
File diff suppressed because it is too large Load Diff
+375 -260
View File
File diff suppressed because it is too large Load Diff
+379 -264
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+385 -270
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+400 -285
View File
File diff suppressed because it is too large Load Diff
+375 -260
View File
File diff suppressed because it is too large Load Diff
+388 -273
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+390 -275
View File
File diff suppressed because it is too large Load Diff
+378 -263
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+373 -258
View File
File diff suppressed because it is too large Load Diff
+373 -258
View File
File diff suppressed because it is too large Load Diff
+377 -262
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+372 -257
View File
File diff suppressed because it is too large Load Diff
+397 -282
View File
File diff suppressed because it is too large Load Diff
+375 -260
View File
File diff suppressed because it is too large Load Diff
+378 -263
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -114,4 +114,5 @@ lms.patches.v2_0.count_in_program
lms.patches.v2_0.fix_scorm_lesson_reference_idx #02-09-2025
lms.patches.v2_0.certified_members_to_certifications #05-10-2025
lms.patches.v2_0.fix_job_application_resume_urls
lms.patches.v2_0.open_to_opportunities
lms.patches.v2_0.open_to_opportunities
lms.patches.v2_0.open_to_work
+12
View File
@@ -0,0 +1,12 @@
import frappe
def execute():
open_to_field_exists = frappe.db.exists("Custom Field", {"dt": "User", "fieldname": "open_to"})
if not open_to_field_exists:
return
open_to_opportunities = frappe.get_all("User", {"open_to": "Opportunities"}, ["name"])
for user in open_to_opportunities:
frappe.db.set_value("User", user.name, "open_to", "Work")
+8 -16
View File
@@ -11,24 +11,16 @@ class TestAuth(FrappeAPITestCase, BaseTestUtils):
self.normal_user = self._create_user("normal-user@example.com", "Normal", "User", ["LMS Student"])
def test_allowed_path(self):
site_url = frappe.utils.get_site_url(frappe.local.site)
headers = {"Authorization": "Bearer set_test_example_user"}
url = site_url + "/api/method/lms.lms.utils.get_courses"
response = self.get(
url,
headers=headers,
)
self.assertNotEqual(response.json.get("exc_type"), "PermissionError")
frappe.form_dict.cmd = "ping"
frappe.session.user = self.normal_user.name
authenticate()
frappe.session.user = "Administrator"
def test_not_allowed_path(self):
site_url = frappe.utils.get_site_url(frappe.local.site)
headers = {"Authorization": "Bearer set_test_example_user"}
url = site_url + "/api/method/frappe.auth.get_logged_user"
response = self.get(
url,
headers=headers,
)
self.assertEqual(response.json.get("exc_type"), "PermissionError")
frappe.form_dict.cmd = "frappe.auth.get_logged_user"
frappe.session.user = self.normal_user.name
self.assertRaises(frappe.PermissionError, authenticate)
frappe.session.user = "Administrator"
def tearDown(self):
BaseTestUtils.tearDown(self)