Skip to content

Commit 3260e3a

Browse files
zee-bitneiljp
authored andcommitted
helper/model: Add footer notification for message sent outside narrow.
This commit generalizes the code for footer notification when a message is sent/edited outside the current narrow. This will give the user a pointer as to why the message disappeared from the screen. The code is hooked to the part where message request is sent to the server, hence preventing the extra check for user_id being same as message_sender_id. Tests amended. Fixes #781.
1 parent 8c27df5 commit 3260e3a

File tree

4 files changed

+108
-7
lines changed

4 files changed

+108
-7
lines changed

tests/helper/test_helper.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
hash_util_decode,
1010
index_messages,
1111
notify,
12+
notify_if_message_sent_outside_narrow,
1213
powerset,
1314
)
1415

@@ -309,6 +310,41 @@ def test_display_error_if_present(mocker, response, footer_updated):
309310
set_footer_text.assert_not_called()
310311

311312

313+
@pytest.mark.parametrize(['req', 'narrow', 'footer_updated'], [
314+
({'type': 'private', 'to': 'foo@gmail.com', 'content': 'bar'},
315+
[['is', 'private']], False),
316+
({'type': 'private', 'to': 'user@abc.com, user@chat.com', 'content': 'Hi'},
317+
[['pm_with', 'user@0abc.com']], True),
318+
({'type': 'private', 'to': 'bar-bar@foo.com', 'content': ':party_parrot:'},
319+
[['pm_with', 'user@abc.com, user@chat.com, bar-bar@foo.com']], True),
320+
({'type': 'stream', 'to': 'ZT', 'subject': '1', 'content': 'foo'},
321+
[['stream', 'ZT'], ['topic', '1']], False),
322+
({'type': 'stream', 'to': 'here', 'subject': 'pytest', 'content': 'py'},
323+
[['stream', 'test here']], True),
324+
({'type': 'stream', 'to': '|new_stream|', 'subject': '(no topic)',
325+
'content': 'Hi `|new_stream|`'}, [], False),
326+
({'type': 'stream', 'to': 'zulip-terminal', 'subject': 'issue#T781',
327+
'content': 'Added tests'}, [['is', 'starred']], True),
328+
({'type': 'private', 'to': '2@aBd%8@random.com', 'content': 'fist_bump'},
329+
[['is', 'mentioned']], True),
330+
({'type': 'stream', 'to': 'PTEST', 'subject': 'TEST', 'content': 'Test'},
331+
[['stream', 'PTEST'], ['search', 'FOO']], True)
332+
])
333+
def test_notify_if_message_sent_outside_narrow(mocker, req, narrow,
334+
footer_updated):
335+
controller = mocker.Mock()
336+
set_footer_text = controller.view.set_footer_text
337+
controller.model.narrow = narrow
338+
339+
notify_if_message_sent_outside_narrow(req, controller)
340+
341+
if footer_updated:
342+
set_footer_text.assert_called_once_with(
343+
'Message is sent outside of current narrow.', 3)
344+
else:
345+
set_footer_text.assert_not_called()
346+
347+
312348
@pytest.mark.parametrize('quoted_string, expected_unquoted_string', [
313349
('(no.20topic)', '(no topic)'),
314350
('.3Cstrong.3Exss.3C.2Fstrong.3E', '<strong>xss</strong>'),

tests/model/test_model.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def mock_external_classes(self, mocker: Any) -> None:
2323
mocker.patch('zulipterminal.model.Model._start_presence_updates')
2424
self.display_error_if_present = mocker.patch(
2525
'zulipterminal.model.display_error_if_present')
26+
self.notify_if_message_sent_outside_narrow = mocker.patch(
27+
'zulipterminal.model.notify_if_message_sent_outside_narrow')
2628

2729
@pytest.fixture
2830
def model(self, mocker, initial_data, user_profile,
@@ -481,6 +483,9 @@ def test_send_private_message(self, mocker, model,
481483
assert result == return_value
482484
self.display_error_if_present.assert_called_once_with(response,
483485
self.controller)
486+
if result == 'success':
487+
self.notify_if_message_sent_outside_narrow.assert_called_once_with(
488+
req, self.controller)
484489

485490
def test_send_private_message_with_no_recipients(self, model,
486491
content="hi!",
@@ -507,6 +512,10 @@ def test_send_stream_message(self, mocker, model,
507512
self.display_error_if_present.assert_called_once_with(response,
508513
self.controller)
509514

515+
if result == 'success':
516+
self.notify_if_message_sent_outside_narrow.assert_called_once_with(
517+
req, self.controller)
518+
510519
@pytest.mark.parametrize('response, return_value', [
511520
({'result': 'success'}, True),
512521
({'result': 'some_failure'}, False),
@@ -530,23 +539,38 @@ def test_update_private_message(self, mocker, model,
530539
({'result': 'success'}, True),
531540
({'result': 'some_failure'}, False),
532541
])
533-
@pytest.mark.parametrize('req', [
542+
@pytest.mark.parametrize('req, old_topic, footer_updated', [
543+
({'message_id': 1, 'propagate_mode': 'change_one',
544+
'content': 'hi!', 'topic': 'Some topic'}, 'Some topic', False),
534545
({'message_id': 1, 'propagate_mode': 'change_one',
535-
'content': 'hi!', 'topic': 'Some topic'}),
546+
'topic': 'Topic change'}, 'Old topic', True),
547+
({'message_id': 1, 'propagate_mode': 'change_all',
548+
'topic': 'Old topic'}, 'Old topic', False),
549+
({'message_id': 1, 'propagate_mode': 'change_later',
550+
'content': ':smile:', 'topic': 'terminal'}, 'terminal', False),
536551
({'message_id': 1, 'propagate_mode': 'change_one',
537-
'topic': 'Topic change'}),
552+
'content': 'Hey!', 'topic': 'grett'}, 'greet', True),
553+
({'message_id': 1, 'propagate_mode': 'change_all',
554+
'content': 'Lets party!', 'topic': 'party'}, 'lets_party', True),
538555
])
539556
def test_update_stream_message(self, mocker, model,
540557
response, return_value,
541-
req):
558+
req, old_topic, footer_updated):
542559
self.client.update_message = mocker.Mock(return_value=response)
560+
model.index['messages'][req['message_id']]['subject'] = old_topic
543561

544562
result = model.update_stream_message(**req)
545563

546564
self.client.update_message.assert_called_once_with(req)
547565
assert result == return_value
548566
self.display_error_if_present.assert_called_once_with(response,
549567
self.controller)
568+
set_footer_text = model.controller.view.set_footer_text
569+
if result and footer_updated:
570+
set_footer_text.assert_called_once_with(
571+
"You changed a message's topic.", 3)
572+
else:
573+
set_footer_text.assert_not_called()
550574

551575
# NOTE: This tests only getting next-unread, not a fixed anchor
552576
def test_success_get_messages(self, mocker, messages_successful_response,

zulipterminal/helper.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import lxml.html
2626
from typing_extensions import Literal, TypedDict
2727

28-
from zulipterminal.api_types import Message
28+
from zulipterminal.api_types import Composition, Message
2929

3030

3131
MACOS = platform.system() == "Darwin"
@@ -651,6 +651,31 @@ def display_error_if_present(response: Dict[str, Any], controller: Any
651651
controller.view.set_footer_text(response['msg'], 3)
652652

653653

654+
def check_narrow_and_notify(outer_narrow: List[Any],
655+
inner_narrow: List[Any],
656+
controller: Any) -> None:
657+
current_narrow = controller.model.narrow
658+
659+
if (current_narrow != [] and current_narrow != outer_narrow
660+
and current_narrow != inner_narrow):
661+
controller.view.set_footer_text(
662+
'Message is sent outside of current narrow.', 3)
663+
664+
665+
def notify_if_message_sent_outside_narrow(message: Composition,
666+
controller: Any) -> None:
667+
current_narrow = controller.model.narrow
668+
669+
if message['type'] == 'stream':
670+
stream_narrow = [['stream', message['to']]]
671+
topic_narrow = stream_narrow + [['topic', message['subject']]]
672+
check_narrow_and_notify(stream_narrow, topic_narrow, controller)
673+
elif message['type'] == 'private':
674+
pm_narrow = [['is', 'private']]
675+
pm_with_narrow = [['pm_with', ",".join(message['to'])]]
676+
check_narrow_and_notify(pm_narrow, pm_with_narrow, controller)
677+
678+
654679
def hash_util_decode(string: str) -> str:
655680
"""
656681
Returns a decoded string given a hash_util_encode() [present in

zulipterminal/model.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
index_messages,
4444
initial_index,
4545
notify,
46+
notify_if_message_sent_outside_narrow,
4647
set_count,
4748
)
4849
from zulipterminal.ui_tools.utils import create_msg_box_list
@@ -391,7 +392,12 @@ def send_private_message(self, recipients: List[str],
391392
)
392393
response = self.client.send_message(composition)
393394
display_error_if_present(response, self.controller)
394-
return response['result'] == 'success'
395+
message_was_sent = response['result'] == 'success'
396+
if message_was_sent:
397+
notify_if_message_sent_outside_narrow(
398+
composition, self.controller,
399+
)
400+
return message_was_sent
395401
else:
396402
raise RuntimeError('Empty recipients list.')
397403

@@ -405,7 +411,10 @@ def send_stream_message(self, stream: str, topic: str,
405411
)
406412
response = self.client.send_message(composition)
407413
display_error_if_present(response, self.controller)
408-
return response['result'] == 'success'
414+
message_was_sent = response['result'] == 'success'
415+
if message_was_sent:
416+
notify_if_message_sent_outside_narrow(composition, self.controller)
417+
return message_was_sent
409418

410419
def update_private_message(self, msg_id: int, content: str) -> bool:
411420
request = {
@@ -429,6 +438,13 @@ def update_stream_message(self, topic: str, message_id: int,
429438

430439
response = self.client.update_message(request)
431440
display_error_if_present(response, self.controller)
441+
if response['result'] == 'success':
442+
old_topic = self.index['messages'][message_id].get('subject', None)
443+
new_topic = request['topic']
444+
view = self.controller.view
445+
if old_topic != new_topic:
446+
view.set_footer_text("You changed a message's topic.", 3)
447+
432448
return response['result'] == 'success'
433449

434450
def fetch_custom_emojis(self) -> NamedEmojiData:

0 commit comments

Comments
 (0)