Skip to content

Commit 126ab37

Browse files
committed
buttons: Add support for parsing, detecting and narrowing PM links.
This commit adds conditional checks in `_parse_narrow_link` to detect PM narrow links. An additonal parameter user_id is facilitated to `_parse_narrow_link` (since it's a class method) for PM recipients handling in `decode_pm_data`. On successful detection, the narrow is switched to the respective PM message via `_switch_narrow_to`. NOTE: A PM narrow can be either "all PMs" (not near) or a "specific PM conversation" (near). Tests added.
1 parent b69fb42 commit 126ab37

File tree

2 files changed

+153
-5
lines changed

2 files changed

+153
-5
lines changed

tests/ui_tools/test_buttons.py

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,56 @@ def test__decode_message_id(self, message_id, expected_return_value):
444444
"stream": {"stream_id": 1, "stream_name": None},
445445
},
446446
),
447+
(
448+
SERVER_URL + "/#narrow/pm-with/1,2-pm",
449+
{
450+
"narrow": "pm-with",
451+
"pm_with": {"type": Literal["pm"], "recipient_ids": [1, 2]},
452+
},
453+
),
454+
(
455+
SERVER_URL + "/#narrow/pm-with/1,2-group",
456+
{
457+
"narrow": "pm-with",
458+
"pm_with": {"type": Literal["pm"], "recipient_ids": [1, 2]},
459+
},
460+
),
461+
(
462+
SERVER_URL + "/#narrow/pm-with/1-user1",
463+
{
464+
"narrow": "pm-with",
465+
"pm_with": {"type": Literal["pm"], "recipient_ids": [1]},
466+
},
467+
),
468+
(
469+
SERVER_URL + "/#narrow/pm-with/1-bot-name",
470+
{
471+
"narrow": "pm-with",
472+
"pm_with": {"type": Literal["pm"], "recipient_ids": [1]},
473+
},
474+
),
475+
(
476+
SERVER_URL + "/#narrow/pm-with/1,2-pm/near/1",
477+
{
478+
"narrow": "pm-with:near",
479+
"message_id": 1,
480+
"pm_with": {"type": Literal["pm"], "recipient_ids": [1, 2]},
481+
},
482+
),
483+
(
484+
SERVER_URL + "/#narrow/pm-with/1,2,3-pm",
485+
{
486+
"narrow": "pm-with",
487+
"pm_with": {"type": Literal["group"], "recipient_ids": [1, 2, 3]},
488+
},
489+
),
490+
(
491+
SERVER_URL + "/#narrow/pm-with/1,2,3-group",
492+
{
493+
"narrow": "pm-with",
494+
"pm_with": {"type": Literal["group"], "recipient_ids": [1, 2, 3]},
495+
},
496+
),
447497
(SERVER_URL + "/#narrow/foo", {}),
448498
(SERVER_URL + "/#narrow/stream/", {}),
449499
(SERVER_URL + "/#narrow/stream/1-Stream-1/topic/", {}),
@@ -456,6 +506,13 @@ def test__decode_message_id(self, message_id, expected_return_value):
456506
"topic_narrow_link",
457507
"stream_near_narrow_link",
458508
"topic_near_narrow_link",
509+
"pm_with_two_recipients_narrow_link",
510+
"group_pm_with_two_recipients_narrow_link",
511+
"pm_exposed_format_1_narrow_link",
512+
"pm_with_bot_exposed_format_1_narrow_link",
513+
"common_pm_near_narrow_link",
514+
"pm_with_more_than_two_recipients_narrow_link",
515+
"group_pm_with_more_than_two_recipients_narrow_link",
459516
"invalid_narrow_link_1",
460517
"invalid_narrow_link_2",
461518
"invalid_narrow_link_3",
@@ -464,7 +521,7 @@ def test__decode_message_id(self, message_id, expected_return_value):
464521
],
465522
)
466523
def test__parse_narrow_link(self, link, expected_parsed_link):
467-
return_value = MessageLinkButton._parse_narrow_link(link)
524+
return_value = MessageLinkButton._parse_narrow_link(link, 1)
468525

469526
assert return_value == expected_parsed_link
470527

@@ -696,7 +753,12 @@ def test__validate_and_patch_stream_data(
696753
assert error == expected_error
697754

698755
@pytest.mark.parametrize(
699-
"parsed_link, narrow_to_stream_called, narrow_to_topic_called",
756+
[
757+
"parsed_link",
758+
"narrow_to_stream_called",
759+
"narrow_to_topic_called",
760+
"narrow_to_user_called",
761+
],
700762
[
701763
(
702764
{
@@ -705,6 +767,7 @@ def test__validate_and_patch_stream_data(
705767
},
706768
True,
707769
False,
770+
False,
708771
),
709772
(
710773
{
@@ -714,6 +777,7 @@ def test__validate_and_patch_stream_data(
714777
},
715778
False,
716779
True,
780+
False,
717781
),
718782
(
719783
{
@@ -723,6 +787,7 @@ def test__validate_and_patch_stream_data(
723787
},
724788
True,
725789
False,
790+
False,
726791
),
727792
(
728793
{
@@ -733,29 +798,83 @@ def test__validate_and_patch_stream_data(
733798
},
734799
False,
735800
True,
801+
False,
802+
),
803+
(
804+
{
805+
"narrow": "pm-with",
806+
"pm_with": {"type": Literal["pm"], "recipient_ids": [11, 12]},
807+
},
808+
False,
809+
False,
810+
True,
811+
),
812+
(
813+
{
814+
"narrow": "pm-with",
815+
"pm_with": {
816+
"type": Literal["group"],
817+
"recipient_ids": [11, 12, 13],
818+
},
819+
},
820+
False,
821+
False,
822+
True,
823+
),
824+
(
825+
{
826+
"narrow": "pm-with:near",
827+
"message_id": 1,
828+
"pm_with": {"type": Literal["pm"], "recipient_ids": [11, 12]},
829+
},
830+
False,
831+
False,
832+
True,
833+
),
834+
(
835+
{
836+
"narrow": "pm-with:near",
837+
"message_id": 1,
838+
"pm_with": {
839+
"type": Literal["group"],
840+
"recipient_ids": [11, 12, 13],
841+
},
842+
},
843+
False,
844+
False,
845+
True,
736846
),
737847
],
738848
ids=[
739849
"stream_narrow",
740850
"topic_narrow",
741851
"stream_near_narrow",
742852
"topic_near_narrow",
853+
"pm_narrow",
854+
"group_pm_narrow",
855+
"pm_near_narrow",
856+
"group_pm_near_narrow",
743857
],
744858
)
745859
def test__switch_narrow_to(
746860
self,
747861
parsed_link,
748862
narrow_to_stream_called,
749863
narrow_to_topic_called,
864+
narrow_to_user_called,
865+
_all_users_by_id,
750866
):
751867
mocked_button = self.message_link_button()
868+
# For PM narrow switch
869+
mocked_button.model._all_users_by_id = _all_users_by_id
752870

753871
mocked_button._switch_narrow_to(parsed_link)
754872

755873
assert (
756874
mocked_button.controller.narrow_to_stream.called == narrow_to_stream_called
757875
)
758876
assert mocked_button.controller.narrow_to_topic.called == narrow_to_topic_called
877+
assert mocked_button.controller.narrow_to_user.called == narrow_to_user_called
759878

760879
@pytest.mark.parametrize(
761880
"error, report_error_called, _switch_narrow_to_called, exit_popup_called",

zulipterminal/ui_tools/buttons.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def _decode_pm_data(encoded_pm_data: str, user_id: int) -> DecodedPM:
391391
recipient_ids_list = list(map(int, recipient_ids.split(",")))
392392

393393
no_of_recipients = len(recipient_ids_list)
394-
# Bump no. of recipients tp include current user_id if not already
394+
# Bump no. of recipients to include current user_id if not already
395395
# present
396396
if user_id not in recipient_ids_list:
397397
no_of_recipients += 1
@@ -413,7 +413,7 @@ def _decode_message_id(message_id: str) -> Optional[int]:
413413
return None
414414

415415
@classmethod
416-
def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
416+
def _parse_narrow_link(cls, link: str, user_id: int) -> ParsedNarrowLink:
417417
"""
418418
Returns either a dict with narrow parameters for supported links or an
419419
empty dict.
@@ -473,6 +473,19 @@ def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink:
473473
message_id=message_id,
474474
)
475475

476+
elif (
477+
len_fragments == 5 and fragments[1] == "pm-with" and fragments[3] == "near"
478+
):
479+
pm_data = cls._decode_pm_data(fragments[2], user_id)
480+
message_id = cls._decode_message_id(fragments[4])
481+
parsed_link = dict(
482+
narrow="pm-with:near", pm_with=pm_data, message_id=message_id
483+
)
484+
485+
elif len_fragments == 3 and fragments[1] == "pm-with":
486+
pm_data = cls._decode_pm_data(fragments[2], user_id)
487+
parsed_link = dict(narrow="pm-with", pm_with=pm_data)
488+
476489
return parsed_link
477490

478491
def _validate_and_patch_stream_data(self, parsed_link: ParsedNarrowLink) -> str:
@@ -561,13 +574,29 @@ def _switch_narrow_to(self, parsed_link: ParsedNarrowLink) -> None:
561574
topic_name=parsed_link["topic_name"],
562575
contextual_message_id=parsed_link["message_id"],
563576
)
577+
elif "pm-with:near" == narrow:
578+
emails = list(
579+
self.model._all_users_by_id.get(user_id)["email"]
580+
for user_id in parsed_link["pm_with"]["recipient_ids"]
581+
)
582+
self.controller.narrow_to_user(
583+
recipient_emails=emails,
584+
contextual_message_id=parsed_link["message_id"],
585+
)
586+
587+
elif "pm-with" == narrow:
588+
emails = list(
589+
self.model._all_users_by_id.get(user_id)["email"]
590+
for user_id in parsed_link["pm_with"]["recipient_ids"]
591+
)
592+
self.controller.narrow_to_user(recipient_emails=emails)
564593

565594
def handle_narrow_link(self) -> None:
566595
"""
567596
Narrows to the respective narrow if the narrow link is valid or updates
568597
the footer with an appropriate validation error message.
569598
"""
570-
parsed_link = self._parse_narrow_link(self.link)
599+
parsed_link = self._parse_narrow_link(self.link, self.model.user_id)
571600
error = self._validate_narrow_link(parsed_link)
572601

573602
if error:

0 commit comments

Comments
 (0)