Skip to content

Commit d9896cb

Browse files
committed
buttons: Add support for PM narrow in MessageLinkButton.
Helper method added: *_decode_pm_data(). The near parameter is used to set focus to a particular message (using the anchor) while switching narrow. Tests added and amended.
1 parent 0b88ecb commit d9896cb

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

tests/ui_tools/test_buttons.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Any, Dict
22

33
import pytest
4+
from typing_extensions import Literal
45
from urwid import AttrMap, Overlay
56

67
from zulipterminal.config.keys import keys_for_command
@@ -405,6 +406,21 @@ def test__decode_stream_data(self, stream_data, expected_response):
405406

406407
assert return_value == expected_response
407408

409+
@pytest.mark.parametrize('pm_data, expected_response', [
410+
('1,2-pm', dict(recipient_ids=[1, 2], type=Literal['pm'])),
411+
('1,2,3-group', dict(recipient_ids=[1, 2, 3],
412+
type=Literal['group'])),
413+
],
414+
ids=[
415+
'ordinary_pm',
416+
'group_pm',
417+
]
418+
)
419+
def test__decode_pm_data(self, pm_data, expected_response):
420+
return_value = MessageLinkButton._decode_pm_data(pm_data)
421+
422+
assert return_value == expected_response
423+
408424
@pytest.mark.parametrize('message_id, expected_return_value', [
409425
('1', 1),
410426
('foo', None),
@@ -430,6 +446,9 @@ def test__decode_message_id(self, message_id, expected_return_value):
430446
(SERVER_URL + '/#narrow/stream/1-Stream-1/topic/foo/near/1',
431447
{'narrow': 'stream:topic:near', 'topic_name': 'foo', 'message_id': 1,
432448
'stream': {'stream_id': 1, 'stream_name': None}}),
449+
(SERVER_URL + '/#narrow/pm-with/1,2-pm/near/1',
450+
{'narrow': 'pm-with', 'message_id': 1,
451+
'pm_with': {'type': Literal['pm'], 'recipient_ids': [1, 2]}}),
433452
(SERVER_URL + '/#narrow/foo',
434453
{}),
435454
(SERVER_URL + '/#narrow/stream/',
@@ -447,6 +466,7 @@ def test__decode_message_id(self, message_id, expected_return_value):
447466
'topic_narrow_link',
448467
'stream_near_narrow_link',
449468
'topic_near_narrow_link',
469+
'pm_near_narrow_link',
450470
'invalid_narrow_link_1',
451471
'invalid_narrow_link_2',
452472
'invalid_narrow_link_3',
@@ -629,44 +649,62 @@ def test__validate_and_patch_stream_data(self, stream_dict, parsed_link,
629649
'parsed_link',
630650
'narrow_to_stream_called',
631651
'narrow_to_topic_called',
652+
'narrow_to_user_called',
632653
],
633654
[
634655
({'narrow': 'stream',
635656
'stream': {'stream_id': 1, 'stream_name': 'Stream 1'}},
636657
True,
658+
False,
637659
False),
638660
({'narrow': 'stream:topic', 'topic_name': 'Foo',
639661
'stream': {'stream_id': 1, 'stream_name': 'Stream 1'}},
640662
False,
641-
True),
663+
True,
664+
False),
642665
({'narrow': 'stream:near', 'message_id': 1,
643666
'stream': {'stream_id': 1, 'stream_name': 'Stream 1'}},
644667
True,
668+
False,
645669
False),
646670
({'narrow': 'stream:topic:near', 'topic_name': 'Foo',
647671
'message_id': 1,
648672
'stream': {'stream_id': 1, 'stream_name': 'Stream 1'}},
649673
False,
674+
True,
675+
False),
676+
({'narrow': 'pm-with', 'message_id': 1,
677+
'pm_with': {'type': Literal['pm'], 'recipient_ids': [1, 2]}},
678+
False,
679+
False,
650680
True),
651681
],
652682
ids=[
653683
'stream_narrow',
654684
'topic_narrow',
655685
'stream_near_narrow',
656686
'topic_near_narrow',
687+
'pm_near_narrow',
657688
]
658689
)
659690
def test__switch_narrow_to(self, parsed_link, narrow_to_stream_called,
660-
narrow_to_topic_called,
691+
narrow_to_topic_called, narrow_to_user_called
661692
):
662693
mocked_button = self.message_link_button()
694+
# For PM narrow switch
695+
mocked_button.model.user_id_email_dict = {
696+
697+
698+
}
663699

664700
mocked_button._switch_narrow_to(parsed_link)
665701

666702
assert (mocked_button.controller.narrow_to_stream.called
667703
== narrow_to_stream_called)
668704
assert (mocked_button.controller.narrow_to_topic.called
669705
== narrow_to_topic_called)
706+
assert (mocked_button.controller.narrow_to_user.called
707+
== narrow_to_user_called)
670708

671709
@pytest.mark.parametrize(['error', 'set_footer_text_called',
672710
'_switch_narrow_to_called',

zulipterminal/ui_tools/buttons.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import re
2-
from typing import Any, Callable, Dict, Optional, Tuple, Union, cast
2+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
33
from urllib.parse import urljoin, urlparse
44

55
import urwid
6-
from typing_extensions import TypedDict
6+
from typing_extensions import Literal, TypedDict
77

88
from zulipterminal.config.keys import is_command_key, primary_key_for_command
99
from zulipterminal.config.symbols import (
@@ -277,11 +277,17 @@ def __init__(self, user_id: int, email: str) -> None:
277277
'stream_name': Optional[str],
278278
})
279279

280+
DecodedPM = TypedDict('DecodedPM', {
281+
'type': Literal['pm', 'group'],
282+
'recipient_ids': List[int],
283+
})
284+
280285
ParsedNarrowLink = TypedDict('ParsedNarrowLink', {
281286
'narrow': str,
282287
'stream': DecodedStream,
283288
'topic_name': str,
284289
'message_id': Optional[int],
290+
'pm_with': DecodedPM,
285291
}, total=False)
286292

287293

@@ -331,6 +337,17 @@ def _decode_stream_data(encoded_stream_data: str) -> DecodedStream:
331337
stream_name = hash_util_decode(encoded_stream_data)
332338
return DecodedStream(stream_id=None, stream_name=stream_name)
333339

340+
@staticmethod
341+
def _decode_pm_data(encoded_pm_data: str) -> DecodedPM:
342+
"""
343+
Returns a dict with PM type and IDs of PM recipients.
344+
"""
345+
recipient_ids, pm_type = encoded_pm_data.split('-')
346+
recipient_ids_list = list(map(int, recipient_ids.split(',')))
347+
348+
return DecodedPM(type=Literal[pm_type],
349+
recipient_ids=recipient_ids_list)
350+
334351
@staticmethod
335352
def _decode_message_id(message_id: str) -> Optional[int]:
336353
"""
@@ -356,6 +373,7 @@ def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
356373
# {encoded.20topic.20name}
357374
# d. narrow/stream/[{stream_id}-]{stream-name}/topic/
358375
# {encoded.20topic.20name}/near/{message_id}
376+
# e. narrow/pm-with/[{recipient_ids},]{pm-type}/near/{message_id}
359377
fragments = urlparse(link.rstrip('/')).fragment.split('/')
360378
len_fragments = len(fragments)
361379
parsed_link = ParsedNarrowLink()
@@ -386,6 +404,12 @@ def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
386404
parsed_link = dict(narrow='stream:topic:near', stream=stream_data,
387405
topic_name=topic_name, message_id=message_id)
388406

407+
elif len_fragments == 5 and fragments[1] == 'pm-with':
408+
pm_data = cls._decode_pm_data(fragments[2])
409+
message_id = cls._decode_message_id(fragments[4])
410+
parsed_link = dict(narrow='pm-with', pm_with=pm_data,
411+
message_id=message_id)
412+
389413
return parsed_link
390414

391415
def _validate_and_patch_stream_data(self,
@@ -475,6 +499,13 @@ def _switch_narrow_to(self, parsed_link: ParsedNarrowLink) -> None:
475499
self.topic_name = parsed_link['topic_name']
476500
self.message = dict(id=parsed_link['message_id'])
477501
self.controller.narrow_to_topic(self)
502+
elif 'pm-with' == narrow:
503+
self.message = dict(id=parsed_link['message_id'])
504+
self.recipients_emails = ', '.join(list(
505+
self.model.user_id_email_dict.get(user_id)
506+
for user_id in parsed_link['pm_with']['recipient_ids']
507+
))
508+
self.controller.narrow_to_user(self)
478509

479510
def handle_narrow_link(self) -> None:
480511
"""

0 commit comments

Comments
 (0)