2020-06-11 00:54:34 +02:00
|
|
|
import ujson
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.actions import do_add_alert_words, do_remove_alert_words
|
|
|
|
from zerver.lib.alert_words import alert_words_in_realm, user_alert_words
|
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
|
|
from zerver.lib.test_helpers import most_recent_message, most_recent_usermessage
|
|
|
|
from zerver.models import UserProfile
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
|
|
|
|
class AlertWordTests(ZulipTestCase):
|
2020-04-09 21:51:58 +02:00
|
|
|
interesting_alert_word_list = ['alert', 'multi-word word', '☃']
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
def get_user(self) -> UserProfile:
|
|
|
|
# One nice thing about Hamlet is that he is
|
|
|
|
# already subscribed to Denmark.
|
|
|
|
return self.example_user('hamlet')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_internal_endpoint(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
params = {
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
'alert_words': ujson.dumps(['milk', 'cookies']),
|
2016-09-14 15:39:41 +02:00
|
|
|
}
|
2017-09-25 23:48:14 +02:00
|
|
|
result = self.client_post('/json/users/me/alert_words', params)
|
2016-09-14 15:39:41 +02:00
|
|
|
self.assert_json_success(result)
|
2020-07-09 17:25:44 +02:00
|
|
|
|
2016-09-14 15:39:41 +02:00
|
|
|
words = user_alert_words(user)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(words), {'milk', 'cookies'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_default_no_words(self) -> None:
|
2016-09-14 15:39:41 +02:00
|
|
|
"""
|
|
|
|
Users start out with no alert words.
|
|
|
|
"""
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
2016-09-14 15:39:41 +02:00
|
|
|
words = user_alert_words(user)
|
|
|
|
self.assertEqual(words, [])
|
|
|
|
|
2020-04-27 20:45:15 +02:00
|
|
|
def test_basics(self) -> None:
|
2016-09-14 15:39:41 +02:00
|
|
|
"""
|
2020-04-27 20:45:15 +02:00
|
|
|
Verifies the basic behavior of modifying alert words.
|
|
|
|
|
|
|
|
Also verifies the cache-flushing behavior.
|
2016-09-14 15:39:41 +02:00
|
|
|
"""
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
2020-04-27 20:45:15 +02:00
|
|
|
realm_alert_words = alert_words_in_realm(user.realm)
|
|
|
|
self.assert_length(realm_alert_words.get(user.id, []), 0)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
# Add several words, including multi-word and non-ascii words.
|
2020-04-27 21:51:39 +02:00
|
|
|
do_add_alert_words(user, self.interesting_alert_word_list)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
words = user_alert_words(user)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(words), set(self.interesting_alert_word_list))
|
2020-04-27 20:45:15 +02:00
|
|
|
realm_alert_words = alert_words_in_realm(user.realm)
|
|
|
|
self.assert_length(realm_alert_words[user.id], 3)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-27 20:04:38 +02:00
|
|
|
# Test the case-insensitivity of adding words
|
2020-05-02 06:24:13 +02:00
|
|
|
do_add_alert_words(user, {"ALert", "ALERT"})
|
2020-04-27 20:04:38 +02:00
|
|
|
words = user_alert_words(user)
|
|
|
|
self.assertEqual(set(words), set(self.interesting_alert_word_list))
|
2020-04-27 20:45:15 +02:00
|
|
|
realm_alert_words = alert_words_in_realm(user.realm)
|
|
|
|
self.assert_length(realm_alert_words[user.id], 3)
|
2020-04-27 20:04:38 +02:00
|
|
|
|
|
|
|
# Test the case-insensitivity of removing words
|
2020-05-02 06:24:13 +02:00
|
|
|
do_remove_alert_words(user, {"ALert"})
|
2020-04-27 20:04:38 +02:00
|
|
|
words = user_alert_words(user)
|
|
|
|
self.assertEqual(set(words), set(self.interesting_alert_word_list) - {'alert'})
|
2020-04-27 20:45:15 +02:00
|
|
|
realm_alert_words = alert_words_in_realm(user.realm)
|
|
|
|
self.assert_length(realm_alert_words[user.id], 2)
|
2020-04-27 20:04:38 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_remove_word(self) -> None:
|
2016-09-14 15:39:41 +02:00
|
|
|
"""
|
2020-04-27 21:51:39 +02:00
|
|
|
Removing alert words works via do_remove_alert_words, even
|
2016-09-14 15:39:41 +02:00
|
|
|
for multi-word and non-ascii words.
|
|
|
|
"""
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-19 01:15:11 +02:00
|
|
|
expected_remaining_alerts = set(self.interesting_alert_word_list)
|
2020-04-27 21:51:39 +02:00
|
|
|
do_add_alert_words(user, self.interesting_alert_word_list)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
for alert_word in self.interesting_alert_word_list:
|
2020-04-27 21:51:39 +02:00
|
|
|
do_remove_alert_words(user, [alert_word])
|
2020-04-19 01:15:11 +02:00
|
|
|
expected_remaining_alerts.remove(alert_word)
|
2016-09-14 15:39:41 +02:00
|
|
|
actual_remaining_alerts = user_alert_words(user)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(actual_remaining_alerts),
|
2020-04-19 01:15:11 +02:00
|
|
|
expected_remaining_alerts)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_realm_words(self) -> None:
|
2016-09-14 15:39:41 +02:00
|
|
|
"""
|
|
|
|
We can gather alert words for an entire realm via
|
|
|
|
alert_words_in_realm. Alerts added for one user do not impact other
|
|
|
|
users.
|
|
|
|
"""
|
2020-07-09 17:25:44 +02:00
|
|
|
user1 = self.get_user()
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-27 21:51:39 +02:00
|
|
|
do_add_alert_words(user1, self.interesting_alert_word_list)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-05-07 21:25:59 +02:00
|
|
|
user2 = self.example_user('othello')
|
2020-04-27 21:51:39 +02:00
|
|
|
do_add_alert_words(user2, ['another'])
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
realm_words = alert_words_in_realm(user2.realm)
|
|
|
|
self.assertEqual(len(realm_words), 2)
|
2020-03-15 14:09:43 +01:00
|
|
|
self.assertEqual(set(realm_words.keys()), {user1.id, user2.id})
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(realm_words[user1.id]),
|
|
|
|
set(self.interesting_alert_word_list))
|
|
|
|
self.assertEqual(set(realm_words[user2.id]), {'another'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_json_list_default(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
result = self.client_get('/json/users/me/alert_words')
|
|
|
|
self.assert_json_success(result)
|
2017-08-16 09:49:11 +02:00
|
|
|
self.assertEqual(result.json()['alert_words'], [])
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2018-07-12 16:23:02 +02:00
|
|
|
def test_json_list_nonempty(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
do_add_alert_words(user, ['one', 'two', 'three'])
|
2018-07-12 16:23:02 +02:00
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
self.login_user(user)
|
2018-07-12 16:23:02 +02:00
|
|
|
result = self.client_get('/json/users/me/alert_words')
|
|
|
|
self.assert_json_success(result)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
|
2018-07-12 16:23:02 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_json_list_add(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-19 01:09:07 +02:00
|
|
|
result = self.client_post('/json/users/me/alert_words',
|
|
|
|
{'alert_words': ujson.dumps(['one ', '\n two', 'three'])})
|
2016-09-14 15:39:41 +02:00
|
|
|
self.assert_json_success(result)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_json_list_remove(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-19 01:09:07 +02:00
|
|
|
result = self.client_post('/json/users/me/alert_words',
|
|
|
|
{'alert_words': ujson.dumps(['one', 'two', 'three'])})
|
2016-09-14 15:39:41 +02:00
|
|
|
self.assert_json_success(result)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-19 01:09:07 +02:00
|
|
|
result = self.client_delete('/json/users/me/alert_words',
|
|
|
|
{'alert_words': ujson.dumps(['one'])})
|
2016-09-14 15:39:41 +02:00
|
|
|
self.assert_json_success(result)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(result.json()['alert_words']), {'two', 'three'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
def message_does_alert(self, user: UserProfile, message: str) -> bool:
|
|
|
|
"""Send a bunch of messages as othello, so our user is notified"""
|
2020-03-07 11:43:05 +01:00
|
|
|
self.send_stream_message(self.example_user("othello"), "Denmark", message)
|
2020-07-09 17:25:44 +02:00
|
|
|
user_message = most_recent_usermessage(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
return 'has_alert_word' in user_message.flags_list()
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_alert_flags(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2020-04-19 01:09:07 +02:00
|
|
|
result = self.client_post('/json/users/me/alert_words',
|
|
|
|
{'alert_words': ujson.dumps(['one', 'two', 'three'])})
|
2016-09-14 15:39:41 +02:00
|
|
|
self.assert_json_success(result)
|
2020-04-19 01:06:46 +02:00
|
|
|
self.assertEqual(set(result.json()['alert_words']), {'one', 'two', 'three'})
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
# Alerts in the middle of messages work.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "Normal alert one time"))
|
2016-09-14 15:39:41 +02:00
|
|
|
# Alerts at the end of messages work.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "Normal alert one"))
|
2016-09-14 15:39:41 +02:00
|
|
|
# Alerts at the beginning of messages work.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "two normal alerts"))
|
2016-09-14 15:39:41 +02:00
|
|
|
# Alerts with surrounding punctuation work.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "This one? should alert"))
|
|
|
|
self.assertTrue(self.message_does_alert(user, "Definitely time for three."))
|
2016-09-14 15:39:41 +02:00
|
|
|
# Multiple alerts in a message work.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "One two three o'clock"))
|
2016-09-14 15:39:41 +02:00
|
|
|
# Alerts are case-insensitive.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertTrue(self.message_does_alert(user, "One o'clock"))
|
|
|
|
self.assertTrue(self.message_does_alert(user, "Case of ONE, won't stop me"))
|
2016-09-14 15:39:41 +02:00
|
|
|
|
|
|
|
# We don't cause alerts for matches in URLs.
|
2020-07-09 17:25:44 +02:00
|
|
|
self.assertFalse(self.message_does_alert(user, "Don't alert on http://t.co/one/ urls"))
|
|
|
|
self.assertFalse(self.message_does_alert(user, "Don't alert on http://t.co/one urls"))
|
2016-09-14 15:39:41 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_update_alert_words(self) -> None:
|
2020-07-09 17:25:44 +02:00
|
|
|
user = self.get_user()
|
|
|
|
self.login_user(user)
|
2016-09-14 18:25:44 +02:00
|
|
|
|
2020-04-19 01:09:07 +02:00
|
|
|
result = self.client_post('/json/users/me/alert_words',
|
|
|
|
{'alert_words': ujson.dumps(['ALERT'])})
|
2016-09-14 18:25:44 +02:00
|
|
|
|
|
|
|
content = 'this is an ALERT for you'
|
2020-07-09 17:25:44 +02:00
|
|
|
self.send_stream_message(user, "Denmark", content)
|
2016-09-14 18:25:44 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
original_message = most_recent_message(user)
|
2016-09-14 18:25:44 +02:00
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
user_message = most_recent_usermessage(user)
|
2016-09-14 18:25:44 +02:00
|
|
|
self.assertIn('has_alert_word', user_message.flags_list())
|
|
|
|
|
2016-12-22 10:17:49 +01:00
|
|
|
result = self.client_patch("/json/messages/" + str(original_message.id), {
|
2016-09-14 18:25:44 +02:00
|
|
|
'message_id': original_message.id,
|
|
|
|
'content': 'new ALERT for you',
|
|
|
|
})
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
user_message = most_recent_usermessage(user)
|
2016-09-14 18:25:44 +02:00
|
|
|
self.assertEqual(user_message.message.content, 'new ALERT for you')
|
|
|
|
self.assertIn('has_alert_word', user_message.flags_list())
|
|
|
|
|
2016-12-22 10:17:49 +01:00
|
|
|
result = self.client_patch("/json/messages/" + str(original_message.id), {
|
2016-09-14 18:25:44 +02:00
|
|
|
'message_id': original_message.id,
|
|
|
|
'content': 'sorry false alarm',
|
|
|
|
})
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2020-07-09 17:25:44 +02:00
|
|
|
user_message = most_recent_usermessage(user)
|
2016-09-14 18:25:44 +02:00
|
|
|
self.assertEqual(user_message.message.content, 'sorry false alarm')
|
|
|
|
self.assertNotIn('has_alert_word', user_message.flags_list())
|