Skip to content

Commit 02931f4

Browse files
committed
refactor: boxes/model: Validate PM recipients more thoroughly.
This commit refactors the `get_invalid_recipients_emails()` method of the model to `check_recipient_validity()` which checks if the recipient's name and email match. This commit follows this strategy: * Ensures that the email and the name are of the same user. * Removes extra text after the email. The recipients information is also tidied for all the valid recipients, by formatting the information to fit the `name <email>` format. The call to this method from boxes.py is also updated accordingly. Test added.
1 parent c31019b commit 02931f4

File tree

3 files changed

+95
-12
lines changed

3 files changed

+95
-12
lines changed

tests/ui_tools/test_boxes.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ def focus_val(x: str) -> int:
718718
if write_box.focus_position == write_box.FOCUS_CONTAINER_HEADER:
719719
write_box.header_write_box.focus_col = (focus_val(
720720
initial_focus_col_name))
721-
write_box.model.get_invalid_recipient_emails.return_value = []
721+
write_box.model.check_recipient_validity.return_value = []
722722
write_box.model.user_dict = mocker.MagicMock()
723723

724724
write_box.keypress(size, tab_key)
@@ -732,6 +732,50 @@ def focus_val(x: str) -> int:
732732
assert (write_box.FOCUS_MESSAGE_BOX_BODY
733733
== focus_val(expected_focus_col_name))
734734

735+
@pytest.mark.parametrize(['raw_recipients', 'tidied_recipients'], [
736+
("Human 1 [email protected]", "Human 1 <[email protected]>"),
737+
("Human 2 [email protected] random text",
738+
"Human 2 <[email protected]>"),
739+
("Human Myself [email protected] random, Human 1 <[email protected]>",
740+
"Human Myself <[email protected]>, Human 1 <[email protected]>"),
741+
("Human Myself <[email protected]>, Human 1 [email protected] random",
742+
"Human Myself <[email protected]>, Human 1 <[email protected]>"),
743+
("Human Myself [email protected] random,"
744+
"Human 1 [email protected] random",
745+
"Human Myself <[email protected]>, Human 1 <[email protected]>"),
746+
("Human Myself [email protected] random, Human 1 [email protected] "
747+
"random, Human 2 [email protected] random",
748+
"Human Myself <[email protected]>, Human 1 <[email protected]>, "
749+
"Human 2 <[email protected]>"),
750+
("Human Myself [email protected], Human 1 [email protected] random, "
751+
752+
"Human Myself <[email protected]>, Human 1 <[email protected]>, "
753+
"Human2 <[email protected]>")
754+
], ids=[
755+
'untidy_with_improper_formatting',
756+
'untidy_with_extra_text',
757+
'untidy_first_recipient_out_of_two',
758+
'untidy_second_recipient_out_of_two',
759+
'two_untidy_recipients',
760+
'three_untidy_recipients',
761+
'untidy_middle_recipient_out_of_three'
762+
])
763+
@pytest.mark.parametrize("tab_key",
764+
keys_for_command("CYCLE_COMPOSE_FOCUS"))
765+
def test_tidying_recipients_on_cycling_out(self, write_box, tab_key,
766+
mocker, raw_recipients,
767+
tidied_recipients, widget_size):
768+
write_box.private_box_view()
769+
write_box.focus_position = write_box.FOCUS_CONTAINER_HEADER
770+
write_box.header_write_box.focus_col = write_box.FOCUS_HEADER_BOX_RECIPIENT
771+
772+
write_box.to_write_box.edit_text = raw_recipients
773+
774+
size = widget_size(write_box)
775+
write_box.keypress(size, tab_key)
776+
777+
assert write_box.to_write_box.edit_text == tidied_recipients
778+
735779
@pytest.mark.parametrize(["msg_type", "expected_box_size"], [
736780
('private', 1),
737781
('stream', 4),

zulipterminal/model.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -914,11 +914,14 @@ def _handle_typing_event(self, event: Event) -> None:
914914
else:
915915
raise RuntimeError("Unknown typing event operation")
916916

917-
def get_invalid_recipient_emails(self, recipient_emails: List[str]
918-
) -> List[str]:
919-
920-
return [email for email in recipient_emails
921-
if email not in self.user_dict]
917+
def check_recipient_validity(self, recipient_name: str,
918+
recipient_email: str,
919+
) -> bool:
920+
if recipient_email and recipient_email in self.user_dict:
921+
verified_name = self.user_dict[recipient_email]['full_name']
922+
if recipient_name == verified_name:
923+
return True
924+
return False
922925

923926
def is_valid_stream(self, stream_name: str) -> bool:
924927
for stream in self.stream_dict.values():

zulipterminal/ui_tools/boxes.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -619,14 +619,50 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
619619
header.focus_col = self.FOCUS_HEADER_BOX_STREAM
620620
else:
621621
self.update_recipient_emails(self.to_write_box)
622-
invalid_emails = self.model.get_invalid_recipient_emails(
623-
self.recipient_emails
622+
tidy_recipients = []
623+
invalid_recipients = []
624+
recipients = [recipient.strip()
625+
for recipient in
626+
self.to_write_box.edit_text.split(',')
627+
if recipient.strip()]
628+
629+
for recipient in recipients:
630+
cleaned_recipient_list = re.findall(
631+
r"^(.*?)(?:\s*?<?([\w\.-]+@[\w\.-]+)>?(.*))?$",
632+
recipient
633+
)
634+
recipient_name, recipient_email, invalid_text = (
635+
cleaned_recipient_list[0]
636+
)
637+
valid = self.model.check_recipient_validity(
638+
recipient_name, recipient_email
639+
)
640+
641+
if valid:
642+
tidy_recipients.append(
643+
f"{recipient_name} <{recipient_email}>"
644+
)
645+
else:
646+
invalid_recipients.append(recipient)
647+
tidy_recipients.append(recipient)
648+
649+
self.to_write_box.edit_text = ", ".join(tidy_recipients)
650+
self.to_write_box.edit_pos = len(
651+
self.to_write_box.edit_text
624652
)
625-
if invalid_emails:
626-
invalid_emails_error = ('Invalid recipient(s) - '
627-
+ ', '.join(invalid_emails))
628-
self.view.set_footer_text(invalid_emails_error, 3)
653+
if invalid_recipients:
654+
invalid_recipients_error = [
655+
'Invalid recipient(s) - '
656+
+ ', '.join(invalid_recipients), ' - Use ',
657+
('code', primary_key_for_command('AUTOCOMPLETE')),
658+
' or ',
659+
('code', primary_key_for_command('AUTOCOMPLETE'
660+
'_REVERSE')),
661+
' to autocomplete.'
662+
]
663+
self.view.set_footer_text(invalid_recipients_error, 3)
629664
return key
665+
630666
users = self.model.user_dict
631667
self.recipient_user_ids = [users[email]['user_id']
632668
for email in

0 commit comments

Comments
 (0)