Skip to content

Commit

Permalink
buttons: Support near stream and near topic narrow in MessageLinkButton.
Browse files Browse the repository at this point in the history
This extends the existing helper methods, _parse_narrow_link(),
_validate_narrow_link() and _switch_narrow_to(), and adds
_decode_message_id() to add support for near stream and near topic
narrow.

The near operator is used to set focus to a particular message (using
the anchor) while switching narrow.

Tests amended.
  • Loading branch information
preetmishra committed Aug 15, 2020
1 parent 6c9937e commit ec28c38
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
57 changes: 57 additions & 0 deletions tests/ui_tools/test_buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,49 @@ def test__decode_stream_data(self, stream_data, expected_response):

assert return_value == expected_response

@pytest.mark.parametrize('message_id, expected_return_value', [
('1', 1),
('foo', None),
])
def test__decode_message_id(self, message_id, expected_return_value):
return_value = MessageLinkButton._decode_message_id(message_id)

assert return_value == expected_return_value

@pytest.mark.parametrize('link, expected_parsed_link', [
(SERVER_URL + '/#narrow/stream/1-Stream-1',
{'narrow': 'stream', 'stream_id': 1}),
(SERVER_URL + '/#narrow/stream/Stream.201',
{'narrow': 'stream', 'stream_name': 'Stream 1'}),
(SERVER_URL + '/#narrow/stream/1-Stream-1/topic/foo.20bar',
{'narrow': 'stream:topic', 'stream_id': 1, 'topic_name': 'foo bar'}),
(SERVER_URL + '/#narrow/stream/1-Stream-1/near/1',
{'narrow': 'stream:near', 'stream_id': 1, 'message_id': 1}),
(SERVER_URL + '/#narrow/stream/1-Stream-1/topic/foo.20bar/near/1',
{'narrow': 'stream:topic:near', 'stream_id': 1,
'topic_name': 'foo bar', 'message_id': 1}),
(SERVER_URL + '/#narrow/foo',
{}),
(SERVER_URL + '/#narrow/stream/',
{}),
(SERVER_URL + '/#narrow/stream/1-Stream-1/topic/',
{}),
(SERVER_URL + '/#narrow/stream/1-Stream-1//near/',
{}),
(SERVER_URL + '/#narrow/stream/1-Stream-1/topic/foo/near/',
{}),
],
ids=[
'modern_stream_narrow_link',
'deprecated_stream_narrow_link',
'topic_narrow_link',
'stream_near_narrow_link',
'topic_near_narrow_link',
'invalid_narrow_link_1',
'invalid_narrow_link_2',
'invalid_narrow_link_3',
'invalid_narrow_link_4',
'invalid_narrow_link_5',
]
)
def test__parse_narrow_link(self, link, expected_parsed_link):
Expand Down Expand Up @@ -164,6 +186,28 @@ def test__parse_narrow_link(self, link, expected_parsed_link):
None,
[],
'Invalid topic name'),
({'narrow': 'stream:near', 'stream_id': 1, 'message_id': 1},
True,
None,
None,
''),
({'narrow': 'stream:near', 'stream_id': 1},
True,
None,
None,
'Invalid message ID'),
({'narrow': 'stream:topic:near', 'stream_id': 1,
'topic_name': 'Valid', 'message_id': 1},
True,
None,
['Valid'],
''),
({'narrow': 'stream:topic:near', 'stream_id': 1,
'topic_name': 'Valid'},
True,
None,
['Valid'],
'Invalid message ID'),
({},
None,
None,
Expand All @@ -177,6 +221,10 @@ def test__parse_narrow_link(self, link, expected_parsed_link):
'invalid_deprecated_stream_narrow_parsed_link',
'valid_topic_narrow_parsed_link',
'invalid_topic_narrow_parsed_link',
'valid_stream_near_narrow_parsed_link',
'invalid_stream_near_narrow_parsed_link',
'valid_topic_near_narrow_parsed_link',
'invalid_topic_near_narrow_parsed_link',
'invalid_narrow_link',
]
)
Expand Down Expand Up @@ -229,10 +277,19 @@ def test__get_stream_data(self, stream_dict, stream_id, stream_name,
({'narrow': 'stream:topic', 'stream_id': 1, 'topic_name': 'Foo'},
False,
True),
({'narrow': 'stream:near', 'stream_id': 1, 'message_id': 1},
True,
False),
({'narrow': 'stream:topic:near', 'stream_id': 1,
'topic_name': 'Foo', 'message_id': 1},
False,
True),
],
ids=[
'stream_narrow',
'topic_narrow',
'stream_near_narrow',
'topic_near_narrow',
]
)
def test__switch_narrow_to(self, mocker, parsed_link,
Expand Down
66 changes: 66 additions & 0 deletions zulipterminal/ui_tools/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,18 @@ def _decode_stream_data(encoded_stream_data: str,
# Deprecated links did not start with the stream ID.
return None, hash_util_decode(encoded_stream_data)

@staticmethod
def _decode_message_id(message_id: str) -> Optional[int]:
"""
Returns either the compatible near message ID or None.
Helper method for _parse_narrow_link().
"""
try:
return int(message_id)
except ValueError:
return None

@classmethod
def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
"""
Expand Down Expand Up @@ -347,6 +359,36 @@ def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
parsed_link['stream_id'] = stream_id
return parsed_link

if (len_fragments == 5 and fragments[1] == 'stream'
and fragments[3] == 'near'):
stream_id, stream_name = cls._decode_stream_data(fragments[2])
message_id = cls._decode_message_id(fragments[4])
parsed_link = {'narrow': 'stream:near'}
if stream_name:
parsed_link['stream_name'] = stream_name
if stream_id:
parsed_link['stream_id'] = stream_id
if message_id:
parsed_link['message_id'] = message_id
return parsed_link

if (len_fragments == 7 and fragments[1] == 'stream'
and fragments[3] == 'topic' and fragments[5] == 'near'):
stream_id, stream_name = cls._decode_stream_data(fragments[2])
topic_name = hash_util_decode(fragments[4])
message_id = cls._decode_message_id(fragments[6])
parsed_link = {
'narrow': 'stream:topic:near',
'topic_name': topic_name,
}
if stream_name:
parsed_link['stream_name'] = stream_name
if stream_id:
parsed_link['stream_id'] = stream_id
if message_id:
parsed_link['message_id'] = message_id
return parsed_link

return dict()

def _validate_narrow_link(self, parsed_link: ParsedNarrowLink) -> str:
Expand Down Expand Up @@ -385,6 +427,13 @@ def _validate_narrow_link(self, parsed_link: ParsedNarrowLink) -> str:
if topic_name not in self.model.topics_in_stream(stream_id):
return 'Invalid topic name'

if 'near' in narrow:
message_id = parsed_link.get('message_id')

# Validate message ID for near.
if not message_id:
return 'Invalid message ID'

return ''

def _get_stream_data(self, stream_id: Optional[int],
Expand Down Expand Up @@ -418,13 +467,30 @@ def _switch_narrow_to(self, parsed_link: ParsedNarrowLink) -> None:
cast(Optional[str], parsed_link.get('stream_name')),
)
self.controller.narrow_to_stream(self)
elif 'stream:near' == narrow:
self.stream_id, self.stream_name = self._get_stream_data(
parsed_link.get('stream_id'),
parsed_link.get('stream_name'),
)
self.message = dict()
self.message['id'] = parsed_link['message_id']
self.controller.narrow_to_stream(self)
elif 'stream:topic' == narrow:
self.stream_id, self.stream_name = self._get_stream_data(
parsed_link.get('stream_id'),
parsed_link.get('stream_name'),
)
self.topic_name = parsed_link['topic_name']
self.controller.narrow_to_topic(self)
elif 'stream:topic:near' == narrow:
self.stream_id, self.stream_name = self._get_stream_data(
parsed_link.get('stream_id'),
parsed_link.get('stream_name'),
)
self.topic_name = parsed_link['topic_name']
self.message = dict()
self.message['id'] = parsed_link['message_id']
self.controller.narrow_to_topic(self)

def handle_narrow_link(self) -> None:
"""
Expand Down

0 comments on commit ec28c38

Please sign in to comment.