knowledgebase: include the topic (application name) in list search
The KB list search matched only shortdescription + keywords, so searching a topic (e.g. "Spotfire", the Application name) surfaced just the one article whose title/keywords contained the word, not the others tied to it by topic. Match the topic too via an appid IN (apps named like the term) subquery - used instead of a join so it does not collide with the sort=topic join, and articles with no app still match on title/keywords.
This commit is contained in:
@@ -29,12 +29,19 @@ def list_articles():
|
||||
|
||||
query = KnowledgeBase.query.filter_by(isactive=True)
|
||||
|
||||
# Search
|
||||
# Search: title, keywords, and the topic (its Application's name). The topic
|
||||
# is matched via an appid subquery instead of a join so it does not collide
|
||||
# with the sort=='topic' join below; articles with no app just miss that
|
||||
# clause and still match on title/keywords.
|
||||
if search := request.args.get('search'):
|
||||
like = f'%{search}%'
|
||||
topic_appids = db.session.query(Application.appid).filter(
|
||||
Application.appname.ilike(like))
|
||||
query = query.filter(
|
||||
db.or_(
|
||||
KnowledgeBase.shortdescription.ilike(f'%{search}%'),
|
||||
KnowledgeBase.keywords.ilike(f'%{search}%')
|
||||
KnowledgeBase.shortdescription.ilike(like),
|
||||
KnowledgeBase.keywords.ilike(like),
|
||||
KnowledgeBase.appid.in_(topic_appids)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -32,3 +32,36 @@ def test_create_requires_shortdescription(client, db, auth_headers):
|
||||
json={'linkurl': 'https://kb.example/x'},
|
||||
headers=auth_headers)
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_search_matches_topic_appname(client, db, auth_headers):
|
||||
"""Searching a topic (Application name) returns every article under it, not
|
||||
just the one whose title/keywords happen to contain the word.
|
||||
|
||||
Regression: KB list search omitted the topic, so a topic-only match (e.g.
|
||||
'Spotfire' as the app) surfaced a single article instead of all of them.
|
||||
"""
|
||||
from shopdb.core.models import Application
|
||||
|
||||
app_row = Application(appname='Spotfire')
|
||||
db.session.add(app_row)
|
||||
db.session.flush()
|
||||
|
||||
# Two articles whose title/keywords do NOT contain 'Spotfire' - only the
|
||||
# topic (appid) ties them to it - plus one that does mention it directly.
|
||||
for payload in [
|
||||
{'shortdescription': 'Dashboard login steps', 'keywords': 'login',
|
||||
'linkurl': 'https://kb.example/a', 'appid': app_row.appid},
|
||||
{'shortdescription': 'Export a visualization', 'keywords': 'export',
|
||||
'linkurl': 'https://kb.example/b', 'appid': app_row.appid},
|
||||
{'shortdescription': 'Spotfire install guide', 'keywords': 'install',
|
||||
'linkurl': 'https://kb.example/c', 'appid': app_row.appid},
|
||||
]:
|
||||
resp = client.post('/api/knowledgebase', json=payload, headers=auth_headers)
|
||||
assert resp.status_code == 201, resp.get_json()
|
||||
|
||||
listing = client.get('/api/knowledgebase?search=Spotfire', headers=auth_headers)
|
||||
assert listing.status_code == 200
|
||||
urls = {a['linkurl'] for a in listing.get_json()['data']}
|
||||
assert {'https://kb.example/a', 'https://kb.example/b',
|
||||
'https://kb.example/c'} <= urls
|
||||
|
||||
Reference in New Issue
Block a user