mirror of https://github.com/zulip/zulip.git
search: Add server support for has:reaction search operator.
Web app support will be a follow-up commit.
This commit is contained in:
parent
436dab0e01
commit
c3408b56f0
|
@ -20,6 +20,13 @@ format used by the Zulip server that they are interacting with.
|
|||
|
||||
## Changes in Zulip 9.0
|
||||
|
||||
**Feature level 249**
|
||||
|
||||
* [`GET /messages`](/api/get-messages), [`GET
|
||||
/messages/matches_narrow`](/api/check-messages-match-narrow): Added
|
||||
new `has:reaction` search operator, matching messages with at least
|
||||
one emoji reaction.
|
||||
|
||||
**Feature level 248**
|
||||
|
||||
* [`POST /typing`](/api/set-typing-status), [`POST /messages`](/api/send-message),
|
||||
|
|
|
@ -51,7 +51,11 @@ important optimization when fetching messages in certain cases (e.g.
|
|||
when [adding the `read` flag to a user's personal
|
||||
messages](/api/update-message-flags-for-narrow)).
|
||||
|
||||
**Changes**: In Zulip 7.0 (feature level 177), support was added
|
||||
**Changes**: In Zulip 9.0 (feature level 249), narrows gained support
|
||||
for a new filter `has:reaction`. This allows clients to retrieve only
|
||||
messages that have at least one reaction.
|
||||
|
||||
In Zulip 7.0 (feature level 177), support was added
|
||||
for three filters related to direct messages: `is:dm`, `dm` and
|
||||
`dm-including`. The `dm` operator replaced and deprecated the
|
||||
`pm-with` operator. The `is:dm` filter replaced and deprecated
|
||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
|||
# Changes should be accompanied by documentation explaining what the
|
||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||
API_FEATURE_LEVEL = 248
|
||||
API_FEATURE_LEVEL = 249
|
||||
|
||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||
# only when going from an old version of the code to a newer version. Bump
|
||||
|
|
|
@ -333,8 +333,24 @@ class NarrowBuilder:
|
|||
return method(query, operand, maybe_negate)
|
||||
|
||||
def by_has(self, query: Select, operand: str, maybe_negate: ConditionTransform) -> Select:
|
||||
if operand not in ["attachment", "image", "link"]:
|
||||
if operand not in ["attachment", "image", "link", "reaction"]:
|
||||
raise BadNarrowOperatorError("unknown 'has' operand " + operand)
|
||||
|
||||
if operand == "reaction":
|
||||
if self.msg_id_column.name == "message_id":
|
||||
# If the initial query uses `zerver_usermessage`
|
||||
check_col = literal_column("zerver_usermessage.message_id", Integer)
|
||||
else:
|
||||
# If the initial query doesn't use `zerver_usermessage`
|
||||
check_col = literal_column("zerver_message.id", Integer)
|
||||
exists_cond = (
|
||||
select([1])
|
||||
.select_from(table("zerver_reaction"))
|
||||
.where(check_col == literal_column("zerver_reaction.message_id", Integer))
|
||||
.exists()
|
||||
)
|
||||
return query.where(maybe_negate(exists_cond))
|
||||
|
||||
col_name = "has_" + operand
|
||||
cond = column(col_name, Boolean)
|
||||
return query.where(maybe_negate(cond))
|
||||
|
|
|
@ -6189,7 +6189,10 @@ paths:
|
|||
subscribed to appropriate streams or use a shared history
|
||||
search narrow with this endpoint.
|
||||
|
||||
**Changes**: In Zulip 7.0 (feature level 177), narrows gained support
|
||||
**Changes**: In Zulip 9.0 (feature level 249), added new `has:reaction`
|
||||
filter, matching messages with at least one emoji reaction.
|
||||
|
||||
In Zulip 7.0 (feature level 177), narrows gained support
|
||||
for three new filters related to direct messages: `is:dm`, `dm` and
|
||||
`dm-including`; replacing and deprecating `is:private`, `pm-with` and
|
||||
`group-pm-with` respectively.
|
||||
|
@ -7059,7 +7062,10 @@ paths:
|
|||
optimization. Including that filter takes advantage of the fact that
|
||||
the server has a database index for unread messages.
|
||||
|
||||
**Changes**: In Zulip 7.0 (feature level 177), narrows gained support
|
||||
**Changes**: In Zulip 9.0 (feature level 249), added new `has:reaction`
|
||||
filter, matching messages with at least one emoji reaction.
|
||||
|
||||
In Zulip 7.0 (feature level 177), narrows gained support
|
||||
for three new filters related to direct messages: `is:dm`, `dm` and
|
||||
`dm-including`; replacing and deprecating `is:private`, `pm-with` and
|
||||
`group-pm-with` respectively.
|
||||
|
@ -7483,7 +7489,10 @@ paths:
|
|||
A structure defining the narrow to check against. See how to
|
||||
[construct a narrow](/api/construct-narrow).
|
||||
|
||||
**Changes**: In Zulip 7.0 (feature level 177), narrows gained support
|
||||
**Changes**: In Zulip 9.0 (feature level 249), added new `has:reaction`
|
||||
filter, matching messages with at least one emoji reaction.
|
||||
|
||||
In Zulip 7.0 (feature level 177), narrows gained support
|
||||
for three new filters related to direct messages: `is:dm`, `dm` and
|
||||
`dm-including`; replacing and deprecating `is:private`, `pm-with` and
|
||||
`group-pm-with` respectively.
|
||||
|
@ -21361,7 +21370,10 @@ components:
|
|||
|
||||
Defaults to `[]`.
|
||||
|
||||
**Changes**: In Zulip 7.0 (feature level 177), narrows gained support
|
||||
**Changes**: In Zulip 9.0 (feature level 249), added new `has:reaction`
|
||||
filter, matching messages with at least one emoji reaction.
|
||||
|
||||
In Zulip 7.0 (feature level 177), narrows gained support
|
||||
for three new filters related to direct messages: `is:dm`, `dm` and
|
||||
`dm-including`; replacing and deprecating `is:private`, `pm-with` and
|
||||
`group-pm-with` respectively.
|
||||
|
|
|
@ -13,6 +13,7 @@ from typing_extensions import override
|
|||
from analytics.lib.counts import COUNT_STATS
|
||||
from analytics.models import RealmCount
|
||||
from zerver.actions.message_edit import do_update_message
|
||||
from zerver.actions.reactions import check_add_reaction
|
||||
from zerver.actions.realm_settings import do_set_realm_property
|
||||
from zerver.actions.uploads import do_claim_attachments
|
||||
from zerver.actions.user_settings import do_change_user_setting
|
||||
|
@ -491,6 +492,20 @@ class NarrowBuilderTest(ZulipTestCase):
|
|||
term = dict(operator="has", operand="link", negated=True)
|
||||
self._do_add_term_test(term, "WHERE NOT has_link")
|
||||
|
||||
def test_add_term_using_has_operator_and_reaction_operand(self) -> None:
|
||||
term = dict(operator="has", operand="reaction")
|
||||
self._do_add_term_test(
|
||||
term,
|
||||
"EXISTS (SELECT 1 \nFROM zerver_reaction \nWHERE zerver_message.id = zerver_reaction.message_id)",
|
||||
)
|
||||
|
||||
def test_add_term_using_has_operator_and_reaction_operand_and_negated(self) -> None:
|
||||
term = dict(operator="has", operand="reaction", negated=True)
|
||||
self._do_add_term_test(
|
||||
term,
|
||||
"NOT (EXISTS (SELECT 1 \nFROM zerver_reaction \nWHERE zerver_message.id = zerver_reaction.message_id))",
|
||||
)
|
||||
|
||||
def test_add_term_using_has_operator_non_supported_operand_should_raise_error(self) -> None:
|
||||
term = dict(operator="has", operand="non_supported")
|
||||
self.assertRaises(BadNarrowOperatorError, self._build_query, term)
|
||||
|
@ -4422,6 +4437,44 @@ class MessageHasKeywordsTest(ZulipTestCase):
|
|||
self.assertFalse(m.called)
|
||||
m.reset_mock()
|
||||
|
||||
def test_has_reaction(self) -> None:
|
||||
self.login("iago")
|
||||
has_reaction_narrow = orjson.dumps([dict(operator="has", operand="reaction")]).decode()
|
||||
|
||||
msg_id = self.send_stream_message(self.example_user("hamlet"), "Denmark", content="Hey")
|
||||
result = self.client_get(
|
||||
"/json/messages",
|
||||
dict(narrow=has_reaction_narrow, anchor=msg_id, num_before=0, num_after=0),
|
||||
)
|
||||
messages = self.assert_json_success(result)["messages"]
|
||||
self.assert_length(messages, 0)
|
||||
check_add_reaction(
|
||||
self.example_user("hamlet"), msg_id, "hamburger", "1f354", "unicode_emoji"
|
||||
)
|
||||
result = self.client_get(
|
||||
"/json/messages",
|
||||
dict(narrow=has_reaction_narrow, anchor=msg_id, num_before=0, num_after=0),
|
||||
)
|
||||
messages = self.assert_json_success(result)["messages"]
|
||||
self.assert_length(messages, 1)
|
||||
|
||||
msg_id = self.send_personal_message(
|
||||
self.example_user("iago"), self.example_user("cordelia"), "Hello Cordelia"
|
||||
)
|
||||
result = self.client_get(
|
||||
"/json/messages",
|
||||
dict(narrow=has_reaction_narrow, anchor=msg_id, num_before=0, num_after=0),
|
||||
)
|
||||
messages = self.assert_json_success(result)["messages"]
|
||||
self.assert_length(messages, 0)
|
||||
check_add_reaction(self.example_user("iago"), msg_id, "hamburger", "1f354", "unicode_emoji")
|
||||
result = self.client_get(
|
||||
"/json/messages",
|
||||
dict(narrow=has_reaction_narrow, anchor=msg_id, num_before=0, num_after=0),
|
||||
)
|
||||
messages = self.assert_json_success(result)["messages"]
|
||||
self.assert_length(messages, 1)
|
||||
|
||||
|
||||
class MessageVisibilityTest(ZulipTestCase):
|
||||
def test_update_first_visible_message_id(self) -> None:
|
||||
|
|
Loading…
Reference in New Issue