def add_alert_words( request: HttpRequest, user_profile: UserProfile, alert_words: List[str] = REQ(validator=check_list(check_string)) ) -> HttpResponse: do_add_alert_words(user_profile, clean_alert_words(alert_words)) return json_success({'alert_words': user_alert_words(user_profile)})
def add_alert_words(request, user_profile, alert_words=REQ(validator=check_list(check_string), default=[])): # type: (HttpRequest, UserProfile, List[str]) -> HttpResponse do_add_alert_words(user_profile, alert_words) return json_success()
def test_basics(self) -> None: """ Verifies the basic behavior of modifying alert words. Also verifies the cache-flushing behavior. """ user = self.example_user('cordelia') realm_alert_words = alert_words_in_realm(user.realm) self.assert_length(realm_alert_words.get(user.id, []), 0) # Add several words, including multi-word and non-ascii words. do_add_alert_words(user, self.interesting_alert_word_list) words = user_alert_words(user) self.assertEqual(set(words), set(self.interesting_alert_word_list)) realm_alert_words = alert_words_in_realm(user.realm) self.assert_length(realm_alert_words[user.id], 3) # Test the case-insensitivity of adding words do_add_alert_words(user, set(["ALert", "ALERT"])) words = user_alert_words(user) self.assertEqual(set(words), set(self.interesting_alert_word_list)) realm_alert_words = alert_words_in_realm(user.realm) self.assert_length(realm_alert_words[user.id], 3) # Test the case-insensitivity of removing words do_remove_alert_words(user, set(["ALert"])) words = user_alert_words(user) self.assertEqual(set(words), set(self.interesting_alert_word_list) - {'alert'}) realm_alert_words = alert_words_in_realm(user.realm) self.assert_length(realm_alert_words[user.id], 2)
def add_alert_words( request: HttpRequest, user_profile: UserProfile, alert_words: List[Text] = REQ(validator=check_list(check_string), default=[]) ) -> HttpResponse: do_add_alert_words(user_profile, clean_alert_words(alert_words)) return json_success()
def add_alert_words( request: HttpRequest, user_profile: UserProfile, alert_words: List[str] = REQ( json_validator=check_list(check_capped_string(100))), ) -> HttpResponse: do_add_alert_words(user_profile, clean_alert_words(alert_words)) return json_success({"alert_words": user_alert_words(user_profile)})
def test_json_list_nonempty(self) -> None: user = self.get_user() do_add_alert_words(user, ['one', 'two', 'three']) self.login_user(user) result = self.client_get('/json/users/me/alert_words') self.assert_json_success(result) self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
def test_json_list_nonempty(self) -> None: hamlet = self.example_user('hamlet') do_add_alert_words(hamlet, ['one', 'two', 'three']) self.login('hamlet') result = self.client_get('/json/users/me/alert_words') self.assert_json_success(result) self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
def test_json_list_nonempty(self) -> None: user = self.get_user() do_add_alert_words(user, ["one", "two", "three"]) self.login_user(user) result = self.client_get("/json/users/me/alert_words") self.assert_json_success(result) self.assertEqual(set(result.json()["alert_words"]), {"one", "two", "three"})
def test_remove_word(self) -> None: """ Removing alert words works via do_remove_alert_words, even for multi-word and non-ascii words. """ user = self.example_user('cordelia') expected_remaining_alerts = set(self.interesting_alert_word_list) do_add_alert_words(user, self.interesting_alert_word_list) for alert_word in self.interesting_alert_word_list: do_remove_alert_words(user, [alert_word]) expected_remaining_alerts.remove(alert_word) actual_remaining_alerts = user_alert_words(user) self.assertEqual(set(actual_remaining_alerts), expected_remaining_alerts)
def test_realm_words(self) -> None: """ We can gather alert words for an entire realm via alert_words_in_realm. Alerts added for one user do not impact other users. """ user1 = self.example_user('cordelia') do_add_alert_words(user1, self.interesting_alert_word_list) user2 = self.example_user('othello') do_add_alert_words(user2, ['another']) realm_words = alert_words_in_realm(user2.realm) self.assertEqual(len(realm_words), 2) self.assertEqual(set(realm_words.keys()), {user1.id, user2.id}) self.assertEqual(set(realm_words[user1.id]), set(self.interesting_alert_word_list)) self.assertEqual(set(realm_words[user2.id]), {'another'})
def test_alert_words_events(self): alert_words_checker = check_dict([ ('type', equals('alert_words')), ('alert_words', check_list(check_string)), ]) events = self.do_test(lambda: do_add_alert_words(self.user_profile, ["alert_word"])) error = alert_words_checker('events[0]', events[0]) self.assert_on_error(error) events = self.do_test(lambda: do_remove_alert_words(self.user_profile, ["alert_word"])) error = alert_words_checker('events[0]', events[0]) self.assert_on_error(error)
def test_realm_words(self) -> None: """ We can gather alert words for an entire realm via alert_words_in_realm. Alerts added for one user do not impact other users. """ # Clear all the words that we got from populate_db. AlertWord.objects.all().delete() user1 = self.get_user() do_add_alert_words(user1, self.interesting_alert_word_list) user2 = self.example_user("othello") do_add_alert_words(user2, ["another"]) realm_words = alert_words_in_realm(user2.realm) self.assertEqual(len(realm_words), 2) self.assertEqual(set(realm_words.keys()), {user1.id, user2.id}) self.assertEqual(set(realm_words[user1.id]), set(self.interesting_alert_word_list)) self.assertEqual(set(realm_words[user2.id]), {"another"})
def add_alert_words(request, user_profile, alert_words=REQ(validator=check_list(check_string), default=[])): do_add_alert_words(user_profile, alert_words) return json_success()
def add_alert_words(request: HttpRequest, user_profile: UserProfile, alert_words: List[str]=REQ(validator=check_list(check_string), default=[]) ) -> HttpResponse: do_add_alert_words(user_profile, clean_alert_words(alert_words)) return json_success()
def test_user_message_filter(self) -> None: # In this test we are basically testing out the logic used out in # do_send_messages() in action.py for filtering the messages for which # UserMessage rows should be created for a soft-deactivated user. recipient_list = [ self.example_user("hamlet"), self.example_user("iago"), self.example_user('cordelia'), ] for user_profile in recipient_list: self.subscribe(user_profile, "Denmark") cordelia = self.example_user('cordelia') sender = self.example_user('iago') stream_name = 'Denmark' topic_name = 'foo' def send_stream_message(content: str) -> None: self.send_stream_message(sender, stream_name, content, topic_name) def send_personal_message(content: str) -> None: self.send_personal_message(sender, self.example_user("hamlet"), content) long_term_idle_user = self.example_user('hamlet') self.send_stream_message(long_term_idle_user, stream_name) with self.assertLogs(level='INFO') as info_logs: do_soft_deactivate_users([long_term_idle_user]) self.assertEqual(info_logs.output, [ 'INFO:root:Soft-deactivated batch of 1 users; 0 remain to process' ]) def assert_um_count(user: UserProfile, count: int) -> None: user_messages = get_user_messages(user) self.assertEqual(len(user_messages), count) def assert_last_um_content(user: UserProfile, content: str, negate: bool = False) -> None: user_messages = get_user_messages(user) if negate: self.assertNotEqual(user_messages[-1].content, content) else: self.assertEqual(user_messages[-1].content, content) # Test that sending a message to a stream with soft deactivated user # doesn't end up creating UserMessage row for deactivated user. general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test Message 1' send_stream_message(message) assert_last_um_content(long_term_idle_user, message, negate=True) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) # Test that sending a message to a stream with soft deactivated user # and push/email notifications on creates a UserMessage row for the # deactivated user. sub = get_subscription(stream_name, long_term_idle_user) sub.push_notifications = True sub.save() general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test private stream message' send_stream_message(message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_last_um_content(long_term_idle_user, message) sub.push_notifications = False sub.save() # Test sending a private message to soft deactivated user creates # UserMessage row. soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test PM' send_personal_message(message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_last_um_content(long_term_idle_user, message) # Test UserMessage row is created while user is deactivated if # user itself is mentioned. general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test @**King Hamlet** mention' send_stream_message(message) assert_last_um_content(long_term_idle_user, message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) # Test UserMessage row is not created while user is deactivated if # anyone is mentioned but the user. general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test @**Cordelia Lear** mention' send_stream_message(message) assert_last_um_content(long_term_idle_user, message, negate=True) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) # Test UserMessage row is created while user is deactivated if # there is a wildcard mention such as @all or @everyone general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test @**all** mention' send_stream_message(message) assert_last_um_content(long_term_idle_user, message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test @**everyone** mention' send_stream_message(message) assert_last_um_content(long_term_idle_user, message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Test @**stream** mention' send_stream_message(message) assert_last_um_content(long_term_idle_user, message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) # Test UserMessage row is not created while user is deactivated if there # is a alert word in message. do_add_alert_words(long_term_idle_user, ['test_alert_word']) general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = 'Testing test_alert_word' send_stream_message(message) assert_last_um_content(long_term_idle_user, message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message) # Test UserMessage row is created while user is deactivated if # message is a me message. general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = '/me says test' send_stream_message(message) assert_last_um_content(long_term_idle_user, message, negate=True) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(cordelia, message)
def test_user_message_filter(self) -> None: # In this test we are basically testing out the logic used out in # do_send_messages() in action.py for filtering the messages for which # UserMessage rows should be created for a soft-deactivated user. AlertWord.objects.all().delete() long_term_idle_user = self.example_user("hamlet") cordelia = self.example_user("cordelia") sender = self.example_user("iago") stream_name = "Brand New Stream" topic_name = "foo" realm_id = cordelia.realm_id self.subscribe(long_term_idle_user, stream_name) self.subscribe(cordelia, stream_name) self.subscribe(sender, stream_name) stream_id = get_stream(stream_name, cordelia.realm).id def send_stream_message(content: str) -> None: self.send_stream_message(sender, stream_name, content, topic_name) def send_personal_message(content: str) -> None: self.send_personal_message(sender, self.example_user("hamlet"), content) self.send_stream_message(long_term_idle_user, stream_name) with self.assertLogs(logger_string, level="INFO") as info_logs: do_soft_deactivate_users([long_term_idle_user]) self.assertEqual( info_logs.output, [ f"INFO:{logger_string}:Soft deactivated user {long_term_idle_user.id}", f"INFO:{logger_string}:Soft-deactivated batch of 1 users; 0 remain to process", ], ) def assert_um_count(user: UserProfile, count: int) -> None: user_messages = get_user_messages(user) self.assert_length(user_messages, count) def assert_last_um_content(user: UserProfile, content: str, negate: bool = False) -> None: user_messages = get_user_messages(user) if negate: self.assertNotEqual(user_messages[-1].content, content) else: self.assertEqual(user_messages[-1].content, content) def assert_num_possible_users( expected_count: int, *, possible_wildcard_mention: bool = False, possibly_mentioned_user_ids: AbstractSet[int] = set(), ) -> None: self.assertEqual( len( get_subscriptions_for_send_message( realm_id=realm_id, stream_id=stream_id, possible_wildcard_mention=possible_wildcard_mention, possibly_mentioned_user_ids=possibly_mentioned_user_ids, )), expected_count, ) def assert_stream_message_sent_to_idle_user( content: str, *, possible_wildcard_mention: bool = False, possibly_mentioned_user_ids: AbstractSet[int] = set(), ) -> None: assert_num_possible_users( expected_count=3, possible_wildcard_mention=possible_wildcard_mention, possibly_mentioned_user_ids=possibly_mentioned_user_ids, ) general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) send_stream_message(content) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(long_term_idle_user, content) assert_last_um_content(cordelia, content) def assert_stream_message_not_sent_to_idle_user( content: str, *, possibly_mentioned_user_ids: AbstractSet[int] = set(), false_alarm_row: bool = False, ) -> None: if false_alarm_row: # We will query for our idle user if he has **ANY** alert # words, but we won't actually write a UserMessage row until # we truly parse the message. We also get false alarms for # messages with quoted mentions. assert_num_possible_users( 3, possibly_mentioned_user_ids=possibly_mentioned_user_ids) else: assert_num_possible_users(2) general_user_msg_count = len(get_user_messages(cordelia)) soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) send_stream_message(content) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count) assert_um_count(cordelia, general_user_msg_count + 1) assert_last_um_content(long_term_idle_user, content, negate=True) assert_last_um_content(cordelia, content) # Test that sending a message to a stream with soft deactivated user # doesn't end up creating UserMessage row for deactivated user. assert_stream_message_not_sent_to_idle_user("Test message 1") sub = get_subscription(stream_name, long_term_idle_user) # Sub settings override user settings. sub.push_notifications = True sub.save() assert_stream_message_sent_to_idle_user("Sub push") sub.push_notifications = False sub.save() assert_stream_message_not_sent_to_idle_user("Sub no push") # Let user defaults take over sub.push_notifications = None sub.save() long_term_idle_user.enable_stream_push_notifications = True long_term_idle_user.save() assert_stream_message_sent_to_idle_user("User push") long_term_idle_user.enable_stream_push_notifications = False long_term_idle_user.save() assert_stream_message_not_sent_to_idle_user("User no push") # Sub settings override user settings. sub.email_notifications = True sub.save() assert_stream_message_sent_to_idle_user("Sub email") sub.email_notifications = False sub.save() assert_stream_message_not_sent_to_idle_user("Sub no email") # Let user defaults take over sub.email_notifications = None sub.save() long_term_idle_user.enable_stream_email_notifications = True long_term_idle_user.save() assert_stream_message_sent_to_idle_user("User email") long_term_idle_user.enable_stream_email_notifications = False long_term_idle_user.save() assert_stream_message_not_sent_to_idle_user("User no email") # Test sending a private message to soft deactivated user creates # UserMessage row. soft_deactivated_user_msg_count = len( get_user_messages(long_term_idle_user)) message = "Test PM" send_personal_message(message) assert_um_count(long_term_idle_user, soft_deactivated_user_msg_count + 1) assert_last_um_content(long_term_idle_user, message) # Test UserMessage row is created while user is deactivated if # user itself is mentioned. assert_stream_message_sent_to_idle_user( "Test @**King Hamlet** mention", possibly_mentioned_user_ids={long_term_idle_user.id}, ) assert_stream_message_not_sent_to_idle_user( "Test `@**King Hamlet**` mention", possibly_mentioned_user_ids={long_term_idle_user.id}, false_alarm_row=True, ) # Test UserMessage row is not created while user is deactivated if # anyone is mentioned but the user. assert_stream_message_not_sent_to_idle_user( "Test @**Cordelia, Lear's daughter** mention") # Test UserMessage row is created while user is deactivated if # there is a wildcard mention such as @all or @everyone assert_stream_message_sent_to_idle_user("Test @**all** mention", possible_wildcard_mention=True) assert_stream_message_sent_to_idle_user("Test @**everyone** mention", possible_wildcard_mention=True) assert_stream_message_sent_to_idle_user("Test @**stream** mention", possible_wildcard_mention=True) assert_stream_message_not_sent_to_idle_user("Test @**bogus** mention") # Test UserMessage row is created while user is deactivated if there # is a alert word in message. do_add_alert_words(long_term_idle_user, ["test_alert_word"]) assert_stream_message_sent_to_idle_user("Testing test_alert_word") do_add_alert_words(cordelia, ["cordelia"]) assert_stream_message_not_sent_to_idle_user("cordelia", false_alarm_row=True) # Test UserMessage row is not created while user is deactivated if # message is a me message. assert_stream_message_not_sent_to_idle_user("/me says test", false_alarm_row=True) # Sanity check after removing the alert word for Hamlet. AlertWord.objects.filter(user_profile=long_term_idle_user).delete() assert_stream_message_not_sent_to_idle_user("no alert words")