From 2b4faaa847a7635b60233ca364a2dcac1caa637e Mon Sep 17 00:00:00 2001 From: Steve Howell Date: Fri, 18 Aug 2017 09:50:54 -0400 Subject: [PATCH] Support non-search queries in /json/messages/matches_narrow. For filters like has:link, where the web app doesn't necessarily want to guess whether incoming messages meet the criteria of the filter, the server is asked to query rows that match the query. Usually these queries are search queries, which have fields for content_matches and subject_matches. Our logic was handling those correctly. Non-search queries were throwing an exception related to tuple unpacking. Now we recognize when those fields are absent and do the proper thing. There are probably situations where the web app should stop hitting this endpoint and just use its own filters. We are making the most defensive fix first. Fixes #6118 --- zerver/tests/test_narrow.py | 36 ++++++++++++++++++++++++++++++++++++ zerver/views/messages.py | 17 ++++++++++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/zerver/tests/test_narrow.py b/zerver/tests/test_narrow.py index 1f5fdfe425..d7e8eee7e8 100644 --- a/zerver/tests/test_narrow.py +++ b/zerver/tests/test_narrow.py @@ -983,6 +983,42 @@ class GetOldMessagesTest(ZulipTestCase): self.assertEqual(link_search_result['messages'][0]['match_content'], '

https://google.com

') + def test_messages_in_narrow_for_non_search(self): + # type: () -> None + email = self.example_email("cordelia") + self.login(email) + + def send(content): + # type: (Text) -> int + msg_id = self.send_message( + sender_name=email, + raw_recipients="Verona", + message_type=Recipient.STREAM, + subject='test_topic', + content=content, + ) + return msg_id + + good_id = send('http://foo.com') + bad_id = send('no link here') + msg_ids = [good_id, bad_id] + send('http://bar.com but not in msg_ids') + + narrow = [ + dict(operator='has', operand='link'), + ] + + raw_params = dict(msg_ids=msg_ids, narrow=narrow) + params = {k: ujson.dumps(v) for k, v in raw_params.items()} + result = self.client_get('/json/messages/matches_narrow', params) + self.assert_json_success(result) + messages = result.json()['messages'] + self.assertEqual(len(list(messages.keys())), 1) + message = messages[str(good_id)] + self.assertIn('a href=', message['match_content']) + self.assertIn('http://foo.com', message['match_content']) + self.assertEqual(message['match_subject'], 'test_topic') + def test_get_messages_with_only_searching_anchor(self): # type: () -> None """ diff --git a/zerver/views/messages.py b/zerver/views/messages.py index 9124602ca7..a5366b998e 100644 --- a/zerver/views/messages.py +++ b/zerver/views/messages.py @@ -1198,8 +1198,19 @@ def messages_in_narrow_backend(request, user_profile, search_fields = dict() for row in query_result: - (message_id, subject, rendered_content, content_matches, subject_matches) = row - search_fields[message_id] = get_search_fields(rendered_content, subject, - content_matches, subject_matches) + message_id = row['message_id'] + subject = row['subject'] + rendered_content = row['rendered_content'] + + if 'content_matches' in row: + content_matches = row['content_matches'] + subject_matches = row['subject_matches'] + search_fields[message_id] = get_search_fields(rendered_content, subject, + content_matches, subject_matches) + else: + search_fields[message_id] = dict( + match_content=rendered_content, + match_subject=subject + ) return json_success({"messages": search_fields})