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:
cproudlock
2026-07-29 10:06:18 -04:00
parent c5ee164565
commit 8dce622392
2 changed files with 43 additions and 3 deletions

View File

@@ -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)
)
)

View File

@@ -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