Merge pull request #1959 from pateljannat/full-text-search-improvements

feat: search by instructor name from command palette
This commit is contained in:
Jannat Patel
2026-01-01 12:30:56 +05:30
committed by GitHub
4 changed files with 165 additions and 43 deletions

View File

@@ -17,9 +17,20 @@ def search_sqlite(query: str):
def prepare_search_results(result):
groups = get_grouped_results(result)
out = []
for key in groups:
groups[key] = remove_duplicates(groups[key])
groups[key].sort(key=lambda x: x.get("modified"), reverse=True)
out.append({"title": key, "items": groups[key]})
return out
def get_grouped_results(result):
roles = frappe.get_roles()
groups = {}
for r in result["results"]:
doctype = r["doctype"]
if doctype == "LMS Course" and can_access_course(r, roles):
@@ -31,12 +42,17 @@ def prepare_search_results(result):
elif doctype == "Job Opportunity" and can_access_job(r, roles):
r["author_info"] = get_instructor_info(doctype, r)
groups.setdefault("Job Opportunities", []).append(r)
return groups
out = []
for key in groups:
out.append({"title": key, "items": groups[key]})
return out
def remove_duplicates(items):
seen = set()
unique_items = []
for item in items:
if item["name"] not in seen:
seen.add(item["name"])
unique_items.append(item)
return unique_items
def can_access_course(course, roles):
@@ -73,10 +89,14 @@ def get_instructor_info(doctype, record):
instructors = frappe.get_all(
"Course Instructor", filters={"parenttype": doctype, "parent": record.get("name")}, pluck="instructor"
)
instructor = record.get("author")
if len(instructors):
instructor = instructors[0]
for ins in instructors:
if ins.split("@")[0] in record.get("content"):
instructor = ins
break
if not instructor:
instructor = instructors[0]
return frappe.db.get_value(
"User",

View File

@@ -52,13 +52,17 @@ class TestCourseEvaluator(UnitTestCase):
return first_date
def calculated_last_date_of_schedule(self, first_date):
last_day = add_days(first_date, 56)
last_day = add_days(getdate(), 56)
offset_monday = (0 - last_day.weekday() + 7) % 7 # 0 for Monday
offset_wednesday = (2 - last_day.weekday() + 7) % 7 # 2 for Wednesday
if offset_monday > offset_wednesday and offset_monday < 4:
if offset_monday < offset_wednesday and offset_monday <= 4:
last_day = add_days(last_day, offset_monday)
else:
elif offset_wednesday <= 4:
last_day = add_days(last_day, offset_wednesday)
else:
last_day = add_days(last_day, min(offset_monday, offset_wednesday) + 7)
return last_day
def test_unavailability_dates(self):

View File

@@ -2,7 +2,7 @@ from contextlib import suppress
import frappe
from frappe.search.sqlite_search import SQLiteSearch, SQLiteSearchIndexMissingError
from frappe.utils import nowdate
from frappe.utils import get_datetime, getdate, nowdate
class LearningSearch(SQLiteSearch):
@@ -17,6 +17,8 @@ class LearningSearch(SQLiteSearch):
"status",
"company_name",
"creation",
"parent",
"parenttype",
],
"tokenizer": "unicode61 remove_diacritics 2 tokenchars '-_'",
}
@@ -60,38 +62,66 @@ class LearningSearch(SQLiteSearch):
{"modified": "creation"},
],
},
"Course Instructor": {
"fields": [
"name",
{"title": "instructor"},
{"content": "instructor"},
"parent",
"parenttype",
"modified",
]
},
}
COURSE_FIELDS = [
"name",
"title",
"description",
"short_introduction",
"category",
"published",
"published_on",
"creation",
"modified",
"owner",
]
BATCH_FIELDS = [
"name",
"title",
"description",
"batch_details",
"category",
"start_date",
"creation",
"modified",
"owner",
"published",
]
JOB_FIELDS = [
"name",
"job_title",
"company_name",
"description",
"creation",
"modified",
"owner",
]
INSTRUCTOR_FIELDS = [
"name",
"instructor",
"parent",
"parenttype",
]
DOCTYPE_FIELDS = {
"LMS Course": [
"name",
"title",
"description",
"short_introduction",
"category",
"creation",
"modified",
"owner",
],
"LMS Batch": [
"name",
"title",
"description",
"batch_details",
"category",
"creation",
"modified",
"owner",
],
"Job Opportunity": [
"name",
"job_title",
"company_name",
"description",
"creation",
"modified",
"owner",
],
"LMS Course": COURSE_FIELDS,
"LMS Batch": BATCH_FIELDS,
"Job Opportunity": JOB_FIELDS,
"Course Instructor": INSTRUCTOR_FIELDS,
}
def build_index(self):
@@ -103,6 +133,58 @@ class LearningSearch(SQLiteSearch):
def get_search_filters(self):
return {}
def prepare_document(self, doc):
document = super().prepare_document(doc)
if not document:
return None
if doc.doctype == "Course Instructor":
document = self.get_instructor_details(doc, document)
else:
if not document.get("modified"):
self.set_modified_date(doc, doc.doctype, document)
return document
def get_instructor_details(self, doc, document):
instructor = frappe.db.get_value("User", doc.instructor, "full_name")
fields = self.COURSE_FIELDS if doc.parenttype == "LMS Course" else self.BATCH_FIELDS
details = frappe.db.get_value(doc.parenttype, doc.parent, fields, as_dict=True)
if details:
document["doctype"] = doc.parenttype
document["name"] = doc.parent
document["title"] = self._process_content(details.title)
document["published"] = details.get("published", 0)
document["content"] = self._process_content(
f"Instructor: {instructor}\n{details.description}\n{doc.instructor}"
)
self.set_modified_date(details, doc.parenttype, document)
if doc.parenttype == "LMS Course":
document["published_on"] = details.get("published_on")
elif doc.parenttype == "LMS Batch":
document["start_date"] = details.get("start_date")
return document
def set_modified_date(self, details, doctype, document):
modified_value = None
if doctype == "LMS Course":
modified_value = details.get("published_on")
elif doctype == "LMS Batch":
modified_value = details.get("start_date")
if not modified_value:
modified_value = frappe.db.get_value(doctype, details.name, "creation")
modified_value = get_datetime(modified_value)
if doctype == "LMS Course":
document["published_on"] = getdate(modified_value)
elif doctype == "LMS Batch":
document["start_date"] = getdate(modified_value)
document["modified"] = modified_value.timestamp()
@SQLiteSearch.scoring_function
def get_doctype_boost(self, row, query, query_words):
doctype = row["doctype"]