This is an automated email from the ASF dual-hosted git repository. brondsem pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/allura.git
commit b403f2154ab058fff30994ec6f415055ac302e0f Author: Dave Brondsema <[email protected]> AuthorDate: Thu Jan 15 11:25:36 2026 -0500 better ticket 'text' indexing into solr (was missing \n after first item, had lots of fields irrelevant to searching) --- ForgeTracker/forgetracker/model/ticket.py | 29 +++++------ .../forgetracker/tests/functional/test_root.py | 6 +-- .../forgetracker/tests/unit/test_ticket_model.py | 57 ++++++++++++++++++++-- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py index b0cba01f1..bbec87215 100644 --- a/ForgeTracker/forgetracker/model/ticket.py +++ b/ForgeTracker/forgetracker/model/ticket.py @@ -588,12 +588,8 @@ def index(self): type_s='Ticket Snapshot', text=self.data.summary) # Tracker uses search with default solr parser. It would match only on - # `text`, so we're appending all other field values into `text`, to match on it too. - result['text'] += '\n'.join([str(v) - for k, v - in result.items() - if k not in ('id', 'project_id_s') - ]) + # `text`, so we're replacing it with many other field values to match on them too + result['text'] += Ticket.text_for_solr(result) return result @@ -718,7 +714,6 @@ def index(self): result.update( title='Ticket #%d: %s' % (self.ticket_num, self.summary), version_i=self.version, - type_s=self.type_s, created_date_dt=self.created_date, ticket_num_i=self.ticket_num, summary_t=self.summary, @@ -749,15 +744,21 @@ def index(self): result['assigned_to_s'] = self.assigned_to.username if self.assigned_to else None # Tracker uses search with default solr parser. It would match only on - # `text`, so we're appending all other field values into `text`, to - # match on it too. - result['text'] += '\n'.join([str(v) - for k, v - in result.items() - if k not in ('id', 'project_id_s') - ]) + # `text`, so we're replacing it with many other field values to match on them too + result['text'] = self.text_for_solr(result) return result + @classmethod + def text_for_solr(cls, result: dict) -> str: + return '\n'.join([ + str(v) + for k, v in result.items() + if k not in ('id', 'mount_point_s', 'url_s', 'type_s', 'title', 'snippet_s') + if not k.startswith(('project_', 'tool_')) # skip project and tool-level stuff + if not k.endswith(('_dt', '_b', '_i')) or k == 'ticket_num_i' # no nums except Ticket# + if v # no None + ]) + @classmethod def attachment_class(cls): return TicketAttachment diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py index 00cab0be8..e24d81111 100644 --- a/ForgeTracker/forgetracker/tests/functional/test_root.py +++ b/ForgeTracker/forgetracker/tests/functional/test_root.py @@ -648,7 +648,7 @@ def test_private_ticket(self): assert 'Public Ticket' in index_response assert 'Private Ticket' in index_response # ...and in search results. - search_response = self.app.get('/p/test/bugs/search/?q=ticket') + search_response = self.app.get('/p/test/bugs/search/?q=open') assert '2 results' in search_response assert 'Private Ticket' in search_response # Unauthorized user doesn't see private ticket on list page... @@ -657,11 +657,11 @@ def test_private_ticket(self): assert '1 results' in r assert 'Private Ticket' not in r # ...or in search results... - r = self.app.get('/p/test/bugs/search/?q=ticket', extra_environ=env) + r = self.app.get('/p/test/bugs/search/?q=open', extra_environ=env) assert '1 results' in r assert 'Private Ticket' not in r # ... or in search feed... - r = self.app.get('/p/test/bugs/search_feed?q=ticket', + r = self.app.get('/p/test/bugs/search_feed?q=open', extra_environ=env) assert 'Private Ticket' not in r # ...and can't get to the private ticket directly. diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py index 2f886a01f..dcd1f32e1 100644 --- a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py +++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py @@ -390,8 +390,55 @@ def test_paged_query_or_search(self, query, search, tsearch): assert tsearch.query_filter_choices.call_count == 0 def test_index(self): - idx = Ticket(ticket_num=2, summary="ticket2", labels=["mylabel", "other"]).index() - assert idx['summary_t'] == 'ticket2' - assert idx['labels_t'] == 'mylabel other' - assert idx['reported_by_s'] == 'test-user' - assert idx['assigned_to_s'] is None # must exist at least + idx = Ticket( + ticket_num=2, + summary="ticket2", + description="this is my descr", + milestone='release 1.0', + labels=["mylabel", "other"], + status='open', + ).index() + created_date_dt = idx.pop('created_date_dt') + assert isinstance(created_date_dt, datetime) + + mod_date_dt = idx.pop('mod_date_dt') + assert isinstance(mod_date_dt, datetime) + + assert idx.pop('project_id_s') + assert idx.pop('id') + + expected_text = ( + 'mylabel other\n2\nticket2\n' + 'release 1.0\nopen\nthis is my descr\ntest-user' + ) + + assert idx == { + # base + 'project_name_t': 'test', + 'project_shortname_t': 'test', + 'tool_name_s': 'tickets', + 'mount_point_s': 'bugs', + 'is_history_b': False, + 'url_s': '/p/test/bugs/2/', + 'type_s': 'Ticket', + 'labels_t': 'mylabel other', + 'deleted_b': False, + # from Ticket + 'title': 'Ticket #2: ticket2', + 'version_i': 0, + 'ticket_num_i': 2, + 'summary_t': 'ticket2', + 'milestone_s': 'release 1.0', + 'status_s': 'open', + 'text': expected_text, + 'snippet_s': 'ticket2', + 'private_b': False, + 'discussion_disabled_b': False, + 'votes_up_i': 0, + 'votes_down_i': 0, + 'votes_total_i': 0, + 'import_id_s': None, + # custom fields + 'reported_by_s': 'test-user', + 'assigned_to_s': None, + }
