narrow: Support string and integer encoding of "id" operator.

Expands support for the message ID operand for id" operator to be either
a string or an integer. Previously, this operand was always validated as
a string.
This commit is contained in:
Lauryn Menard 2023-07-17 15:39:05 +02:00 committed by Tim Abbott
parent 211934a9d9
commit 3255281a83
6 changed files with 70 additions and 15 deletions

View File

@ -20,6 +20,16 @@ format used by the Zulip server that they are interacting with.
## Changes in Zulip 8.0
**Feature level 194**
* [`GET /messages`](/api/get-messages),
[`GET /messages/matches_narrow`](/api/check-messages-match-narrow),
[`POST /message/flags/narrow`](/api/update-message-flags-for-narrow),
[`POST /register`](/api/register-queue):
For [search/narrow filters](/api/construct-narrow) with the `id`
operator, added support for encoding the message ID operand as either
a string or an integer. Previously, only string encoding was supported.
**Feature level 193**
* [`POST /messages/{message_id}/reactions`](/api/add-reaction),

View File

@ -65,12 +65,33 @@ filters did.
## Narrows that use IDs
### Message IDs
The `near` and `id` operators, documented in the help center, use message
IDs for their operands.
* `near:12345`: Search messages around the message with ID `12345`.
* `id:12345`: Search for only message with ID `12345`.
The message ID operand for the `id` operator may be encoded as either a
number or a string. The message ID operand for the `near` operator must
be encoded as a string.
**Changes**: Prior to Zulip 8.0 (feature level 194), the message ID
operand for the `id` operator needed to be encoded as a string.
```json
[
{
"operator": "id",
"operand": 12345
}
]
```
### Stream and user IDs
There are a few additional narrow/search options (new in Zulip 2.1)
that use either stream IDs or user IDs that are not documented in the
help center because they are primarily useful to API clients:

View File

@ -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 = 193
API_FEATURE_LEVEL = 194
# 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

View File

@ -140,13 +140,20 @@ function get_messages_success(data, opts) {
process_result(data, opts);
}
// This function modifies the data.narrow filters to use user IDs
// instead of emails string if it is supported. We currently don't set
// or convert the emails string to user IDs directly into the Filter code
// because doing so breaks the app in various modules that expect emails string.
// This function modifies the data.narrow filters to use integer IDs
// instead of strings if it is supported. We currently don't set or
// convert user emails to user IDs directly in the Filter code
// because doing so breaks the app in various modules that expect a
// string of user emails.
function handle_operators_supporting_id_based_api(data) {
const operators_supporting_ids = new Set(["dm", "pm-with"]);
const operators_supporting_id = new Set(["sender", "group-pm-with", "stream", "dm-including"]);
const operators_supporting_id = new Set([
"id",
"stream",
"sender",
"group-pm-with",
"dm-including",
]);
if (data.narrow === undefined) {
return data;
@ -159,6 +166,12 @@ function handle_operators_supporting_id_based_api(data) {
}
if (operators_supporting_id.has(filter.operator)) {
if (filter.operator === "id") {
// The message ID may not exist locally,
// so send the filter to the server as is.
return filter;
}
if (filter.operator === "stream") {
const stream_id = stream_data.get_stream_id(filter.operand);
if (stream_id !== undefined) {

View File

@ -751,11 +751,17 @@ def narrow_parameter(var_name: str, json: str) -> OptionalNarrowListT:
return dict(operator=elem[0], operand=elem[1])
if isinstance(elem, dict):
# Make sure to sync this list to frontend also when adding a new operator.
# that supports user IDs. Relevant code is located in web/src/message_fetch.js
# in handle_operators_supporting_id_based_api function where you will need to update
# operators_supporting_id, or operators_supporting_ids array.
operators_supporting_id = ["sender", "group-pm-with", "stream", "dm-including"]
# Make sure to sync this list to frontend also when adding a new operator that
# supports integer IDs. Relevant code is located in web/src/message_fetch.js
# in handle_operators_supporting_id_based_api function where you will need to
# update operators_supporting_id, or operators_supporting_ids array.
operators_supporting_id = [
"id",
"stream",
"sender",
"group-pm-with",
"dm-including",
]
operators_supporting_ids = ["pm-with", "dm"]
operators_non_empty_operand = {"search"}

View File

@ -417,10 +417,14 @@ class NarrowBuilderTest(ZulipTestCase):
"WHERE NOT (sender_id = %(sender_id_1)s AND recipient_id = %(recipient_id_1)s OR sender_id = %(sender_id_2)s AND recipient_id = %(recipient_id_2)s OR recipient_id IN (__[POSTCOMPILE_recipient_id_3]))",
)
def test_add_term_using_id_operator(self) -> None:
def test_add_term_using_id_operator_integer(self) -> None:
term = dict(operator="id", operand=555)
self._do_add_term_test(term, "WHERE id = %(param_1)s")
def test_add_term_using_id_operator_string(self) -> None:
term = dict(operator="id", operand="555")
self._do_add_term_test(term, "WHERE id = %(param_1)s")
def test_add_term_using_id_operator_invalid(self) -> None:
term = dict(operator="id", operand="")
self.assertRaises(BadNarrowOperatorError, self._build_query, term)
@ -3412,10 +3416,11 @@ class GetOldMessagesTest(ZulipTestCase):
def test_invalid_narrow_operand_in_dict(self) -> None:
self.login("hamlet")
# str or int is required for "sender", "stream", "dm-including" and "group-pm-with" operators
# str or int is required for "id", "sender", "stream", "dm-including" and "group-pm-with"
# operators
invalid_operands = [["1"], [2], None]
error_msg = 'elem["operand"] is not a string or integer'
for operand in ["sender", "group-pm-with", "stream", "dm-including"]:
for operand in ["id", "sender", "stream", "dm-including", "group-pm-with"]:
self.exercise_bad_narrow_operand_using_dict_api(operand, invalid_operands, error_msg)
# str or int list is required for "dm" and "pm-with" operator
@ -3432,7 +3437,7 @@ class GetOldMessagesTest(ZulipTestCase):
# For others only str is acceptable
invalid_operands = [2, None, [1]]
error_msg = 'elem["operand"] is not a string'
for operand in ["is", "near", "has", "id"]:
for operand in ["is", "near", "has"]:
self.exercise_bad_narrow_operand_using_dict_api(operand, invalid_operands, error_msg)
# Disallow empty search terms