2013-03-20 22:08:48 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2017-08-04 02:25:38 +02:00
|
|
|
from typing import (Any, Dict, Iterable, List, Mapping,
|
2018-05-11 01:39:38 +02:00
|
|
|
Optional, TypeVar, Union)
|
2016-06-15 23:47:22 +02:00
|
|
|
|
2016-09-14 02:08:08 +02:00
|
|
|
from django.http import HttpResponse
|
2017-03-08 12:28:24 +01:00
|
|
|
from django.test import TestCase
|
2012-08-28 18:44:51 +02:00
|
|
|
|
2014-01-27 22:53:36 +01:00
|
|
|
from zerver.lib.test_helpers import (
|
2016-07-15 10:14:51 +02:00
|
|
|
queries_captured, simulated_empty_cache,
|
2017-10-23 22:03:28 +02:00
|
|
|
tornado_redirected_to_list, get_subscription,
|
2016-12-19 08:48:03 +01:00
|
|
|
most_recent_message, make_client, avatar_disk_path,
|
|
|
|
get_test_image_file
|
2014-01-27 22:53:36 +01:00
|
|
|
)
|
2016-11-10 19:30:09 +01:00
|
|
|
from zerver.lib.test_classes import (
|
|
|
|
ZulipTestCase,
|
|
|
|
)
|
2016-07-16 03:56:45 +02:00
|
|
|
from zerver.lib.test_runner import slow
|
2014-01-27 22:53:36 +01:00
|
|
|
|
2014-01-31 23:13:58 +01:00
|
|
|
from zerver.models import UserProfile, Recipient, \
|
2018-06-13 14:10:53 +02:00
|
|
|
Realm, RealmDomain, UserActivity, UserHotspot, \
|
2017-10-28 20:26:11 +02:00
|
|
|
get_user, get_realm, get_client, get_stream, get_stream_recipient, \
|
2018-06-19 10:55:56 +02:00
|
|
|
get_source_profile, Message, get_context_for_message, \
|
2018-09-01 22:39:29 +02:00
|
|
|
ScheduledEmail, check_valid_user_ids, \
|
|
|
|
get_user_by_id_in_realm_including_cross_realm
|
2014-02-07 22:47:30 +01:00
|
|
|
|
2017-02-16 22:35:57 +01:00
|
|
|
from zerver.lib.avatar import avatar_url
|
2016-06-22 10:36:22 +02:00
|
|
|
from zerver.lib.email_mirror import create_missed_message_address
|
2017-11-01 10:04:16 +01:00
|
|
|
from zerver.lib.exceptions import JsonableError
|
2017-07-01 03:56:40 +02:00
|
|
|
from zerver.lib.send_email import send_future_email
|
2017-03-21 18:08:40 +01:00
|
|
|
from zerver.lib.actions import (
|
|
|
|
get_emails_from_user_ids,
|
2017-10-23 22:03:28 +02:00
|
|
|
get_recipient_info,
|
2017-03-21 18:08:40 +01:00
|
|
|
do_deactivate_user,
|
|
|
|
do_reactivate_user,
|
|
|
|
do_change_is_admin,
|
2017-10-24 19:25:50 +02:00
|
|
|
do_create_user,
|
2017-03-21 18:08:40 +01:00
|
|
|
)
|
2018-05-21 19:30:26 +02:00
|
|
|
from zerver.lib.create_user import copy_user_settings
|
2017-10-24 00:07:03 +02:00
|
|
|
from zerver.lib.topic_mutes import add_topic_mute
|
|
|
|
from zerver.lib.stream_topic import StreamTopicTarget
|
2018-06-19 10:55:56 +02:00
|
|
|
from zerver.lib.users import user_ids_to_users, access_user_by_id, \
|
|
|
|
get_accounts_for_email
|
2012-08-28 18:44:51 +02:00
|
|
|
|
2012-09-27 19:58:42 +02:00
|
|
|
from django.conf import settings
|
2017-07-01 03:56:40 +02:00
|
|
|
|
|
|
|
import datetime
|
2017-10-22 03:14:44 +02:00
|
|
|
import mock
|
2013-06-19 20:08:48 +02:00
|
|
|
import os
|
2013-01-10 19:41:49 +01:00
|
|
|
import sys
|
2013-06-20 18:47:19 +02:00
|
|
|
import time
|
2013-06-18 23:55:55 +02:00
|
|
|
import ujson
|
2013-03-14 22:12:25 +01:00
|
|
|
|
2016-06-15 23:47:22 +02:00
|
|
|
K = TypeVar('K')
|
|
|
|
V = TypeVar('V')
|
2017-11-05 10:51:25 +01:00
|
|
|
def find_dict(lst: Iterable[Dict[K, V]], k: K, v: V) -> Dict[K, V]:
|
2014-01-14 20:38:45 +01:00
|
|
|
for dct in lst:
|
|
|
|
if dct[k] == v:
|
|
|
|
return dct
|
2017-03-05 08:17:36 +01:00
|
|
|
raise AssertionError('Cannot find element in list where key %s == %s' % (k, v))
|
2014-01-14 20:38:45 +01:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class PermissionTest(ZulipTestCase):
|
2018-05-15 19:45:31 +02:00
|
|
|
|
|
|
|
def test_do_change_is_admin(self) -> None:
|
|
|
|
"""
|
|
|
|
Ensures change_is_admin raises an AssertionError when invalid permissions
|
|
|
|
are provided to it.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# this should work fine
|
|
|
|
user_profile = self.example_user('hamlet')
|
|
|
|
do_change_is_admin(user_profile, True)
|
|
|
|
|
|
|
|
# this should work a-ok as well
|
|
|
|
do_change_is_admin(user_profile, True, permission='administer')
|
|
|
|
|
|
|
|
# this should "fail" with an AssertionError
|
|
|
|
with self.assertRaises(AssertionError):
|
|
|
|
do_change_is_admin(user_profile, True, permission='totally-not-valid-perm')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_admin_users(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2014-01-22 20:12:29 +01:00
|
|
|
do_change_is_admin(user_profile, False)
|
2013-11-02 15:36:17 +01:00
|
|
|
admin_users = user_profile.realm.get_admin_users()
|
|
|
|
self.assertFalse(user_profile in admin_users)
|
2014-01-22 20:12:29 +01:00
|
|
|
do_change_is_admin(user_profile, True)
|
2013-11-02 15:36:17 +01:00
|
|
|
admin_users = user_profile.realm.get_admin_users()
|
|
|
|
self.assertTrue(user_profile in admin_users)
|
2013-09-30 22:52:04 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_updating_non_existent_user(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
self.login(self.example_email("hamlet"))
|
2017-05-07 17:21:26 +02:00
|
|
|
admin = self.example_user('hamlet')
|
2016-07-13 05:05:55 +02:00
|
|
|
do_change_is_admin(admin, True)
|
|
|
|
|
2018-05-17 19:36:33 +02:00
|
|
|
invalid_user_id = 1000
|
|
|
|
result = self.client_patch('/json/users/{}'.format(invalid_user_id), {})
|
2016-07-13 05:05:55 +02:00
|
|
|
self.assert_json_error(result, 'No such user')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_admin_api(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
self.login(self.example_email("hamlet"))
|
2017-05-07 17:21:26 +02:00
|
|
|
admin = self.example_user('hamlet')
|
|
|
|
user = self.example_user('othello')
|
2014-01-14 16:19:26 +01:00
|
|
|
realm = admin.realm
|
2014-01-22 20:12:29 +01:00
|
|
|
do_change_is_admin(admin, True)
|
2014-01-14 20:38:45 +01:00
|
|
|
|
|
|
|
# Make sure we see is_admin flag in /json/users
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get('/json/users')
|
2014-01-14 20:38:45 +01:00
|
|
|
self.assert_json_success(result)
|
2017-08-17 08:46:17 +02:00
|
|
|
members = result.json()['members']
|
2017-05-25 01:40:26 +02:00
|
|
|
hamlet = find_dict(members, 'email', self.example_email("hamlet"))
|
2014-01-14 20:38:45 +01:00
|
|
|
self.assertTrue(hamlet['is_admin'])
|
2017-05-25 02:08:35 +02:00
|
|
|
othello = find_dict(members, 'email', self.example_email("othello"))
|
2014-01-14 20:38:45 +01:00
|
|
|
self.assertFalse(othello['is_admin'])
|
2014-01-14 16:19:26 +01:00
|
|
|
|
|
|
|
# Giveth
|
|
|
|
req = dict(is_admin=ujson.dumps(True))
|
2014-01-21 19:27:22 +01:00
|
|
|
|
2017-08-04 02:25:38 +02:00
|
|
|
events = [] # type: List[Mapping[str, Any]]
|
2014-01-21 19:27:22 +01:00
|
|
|
with tornado_redirected_to_list(events):
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user("othello").id), req)
|
2014-01-14 16:19:26 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
admin_users = realm.get_admin_users()
|
|
|
|
self.assertTrue(user in admin_users)
|
2014-01-21 19:27:22 +01:00
|
|
|
person = events[0]['event']['person']
|
2017-05-25 02:08:35 +02:00
|
|
|
self.assertEqual(person['email'], self.example_email("othello"))
|
2014-01-21 19:27:22 +01:00
|
|
|
self.assertEqual(person['is_admin'], True)
|
2014-01-14 16:19:26 +01:00
|
|
|
|
|
|
|
# Taketh away
|
|
|
|
req = dict(is_admin=ujson.dumps(False))
|
2014-01-21 19:27:22 +01:00
|
|
|
events = []
|
|
|
|
with tornado_redirected_to_list(events):
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user("othello").id), req)
|
2014-01-14 16:19:26 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
admin_users = realm.get_admin_users()
|
|
|
|
self.assertFalse(user in admin_users)
|
2014-01-21 19:27:22 +01:00
|
|
|
person = events[0]['event']['person']
|
2017-05-25 02:08:35 +02:00
|
|
|
self.assertEqual(person['email'], self.example_email("othello"))
|
2014-01-21 19:27:22 +01:00
|
|
|
self.assertEqual(person['is_admin'], False)
|
2014-01-14 16:19:26 +01:00
|
|
|
|
2016-12-05 06:40:00 +01:00
|
|
|
# Cannot take away from last admin
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2016-12-05 06:40:00 +01:00
|
|
|
req = dict(is_admin=ujson.dumps(False))
|
|
|
|
events = []
|
|
|
|
with tornado_redirected_to_list(events):
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user("hamlet").id), req)
|
2016-12-05 06:40:00 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
admin_users = realm.get_admin_users()
|
|
|
|
self.assertFalse(admin in admin_users)
|
|
|
|
person = events[0]['event']['person']
|
2017-05-25 01:40:26 +02:00
|
|
|
self.assertEqual(person['email'], self.example_email("hamlet"))
|
2016-12-05 06:40:00 +01:00
|
|
|
self.assertEqual(person['is_admin'], False)
|
|
|
|
with tornado_redirected_to_list([]):
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user("iago").id), req)
|
2016-12-05 06:40:00 +01:00
|
|
|
self.assert_json_error(result, 'Cannot remove the only organization administrator')
|
|
|
|
|
2014-01-14 16:19:26 +01:00
|
|
|
# Make sure only admins can patch other user's info.
|
2017-05-25 02:08:35 +02:00
|
|
|
self.login(self.example_email("othello"))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user("hamlet").id), req)
|
2014-01-14 16:19:26 +01:00
|
|
|
self.assert_json_error(result, 'Insufficient permission')
|
|
|
|
|
2018-04-01 01:06:56 +02:00
|
|
|
def test_user_cannot_promote_to_admin(self) -> None:
|
|
|
|
self.login(self.example_email("hamlet"))
|
|
|
|
req = dict(is_admin=ujson.dumps(True))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user('hamlet').id), req)
|
2018-04-01 01:06:56 +02:00
|
|
|
self.assert_json_error(result, 'Insufficient permission')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_admin_user_can_change_full_name(self) -> None:
|
2016-09-27 14:25:52 +02:00
|
|
|
new_name = 'new name'
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2018-05-17 19:36:33 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
2016-09-27 14:25:52 +02:00
|
|
|
req = dict(full_name=ujson.dumps(new_name))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(hamlet.id), req)
|
2018-06-21 14:56:18 +02:00
|
|
|
self.assert_json_success(result)
|
2017-05-07 17:21:26 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
2016-09-27 14:25:52 +02:00
|
|
|
self.assertEqual(hamlet.full_name, new_name)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_non_admin_cannot_change_full_name(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
self.login(self.example_email("hamlet"))
|
2016-09-27 14:25:52 +02:00
|
|
|
req = dict(full_name=ujson.dumps('new name'))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user('othello').id), req)
|
2016-09-27 14:25:52 +02:00
|
|
|
self.assert_json_error(result, 'Insufficient permission')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_admin_cannot_set_long_full_name(self) -> None:
|
2016-09-27 14:25:52 +02:00
|
|
|
new_name = 'a' * (UserProfile.MAX_NAME_LENGTH + 1)
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2016-09-27 14:25:52 +02:00
|
|
|
req = dict(full_name=ujson.dumps(new_name))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user('hamlet').id), req)
|
2016-09-27 14:25:52 +02:00
|
|
|
self.assert_json_error(result, 'Name too long!')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_admin_cannot_set_short_full_name(self) -> None:
|
2017-05-12 04:21:49 +02:00
|
|
|
new_name = 'a'
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2017-05-12 04:21:49 +02:00
|
|
|
req = dict(full_name=ujson.dumps(new_name))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user('hamlet').id), req)
|
2017-05-12 04:21:49 +02:00
|
|
|
self.assert_json_error(result, 'Name too short!')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_admin_cannot_set_full_name_with_invalid_characters(self) -> None:
|
2017-01-16 04:18:42 +01:00
|
|
|
new_name = 'Opheli*'
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2017-01-16 04:18:42 +01:00
|
|
|
req = dict(full_name=ujson.dumps(new_name))
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_patch('/json/users/{}'.format(self.example_user('hamlet').id), req)
|
2017-01-16 04:18:42 +01:00
|
|
|
self.assert_json_error(result, 'Invalid characters in name!')
|
|
|
|
|
2018-06-04 07:04:19 +02:00
|
|
|
def test_access_user_by_id(self) -> None:
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
|
|
|
|
# Must be a valid user ID in the realm
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
access_user_by_id(iago, 1234)
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
access_user_by_id(iago, self.mit_user("sipbtest").id)
|
|
|
|
|
|
|
|
# Can only access bot users if allow_deactivated is passed
|
|
|
|
bot = self.example_user("welcome_bot")
|
|
|
|
access_user_by_id(iago, bot.id, allow_bots=True)
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
access_user_by_id(iago, bot.id)
|
|
|
|
|
|
|
|
# Can only access deactivated users if allow_deactivated is passed
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
do_deactivate_user(hamlet)
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
access_user_by_id(iago, hamlet.id)
|
|
|
|
access_user_by_id(iago, hamlet.id, allow_deactivated=True)
|
|
|
|
|
|
|
|
# Non-admin user can't admin another user
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
access_user_by_id(self.example_user("cordelia"), self.example_user("aaron").id)
|
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class AdminCreateUserTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_create_user_backend(self) -> None:
|
2016-07-12 20:46:55 +02:00
|
|
|
|
|
|
|
# This test should give us complete coverage on
|
|
|
|
# create_user_backend. It mostly exercises error
|
|
|
|
# conditions, and it also does a basic test of the success
|
|
|
|
# path.
|
|
|
|
|
2017-05-07 21:25:59 +02:00
|
|
|
admin = self.example_user('hamlet')
|
|
|
|
admin_email = admin.email
|
2018-03-05 20:19:07 +01:00
|
|
|
realm = admin.realm
|
2016-07-12 20:46:55 +02:00
|
|
|
self.login(admin_email)
|
|
|
|
do_change_is_admin(admin, True)
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict())
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result, "Missing 'email' argument")
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict(
|
2016-07-12 20:46:55 +02:00
|
|
|
email='romeo@not-zulip.com',
|
2017-01-24 06:34:26 +01:00
|
|
|
))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result, "Missing 'password' argument")
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict(
|
2016-07-12 20:46:55 +02:00
|
|
|
email='romeo@not-zulip.com',
|
|
|
|
password='xxxx',
|
2017-01-24 06:34:26 +01:00
|
|
|
))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result, "Missing 'full_name' argument")
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict(
|
2016-07-12 20:46:55 +02:00
|
|
|
email='romeo@not-zulip.com',
|
|
|
|
password='xxxx',
|
|
|
|
full_name='Romeo Montague',
|
2017-01-24 06:34:26 +01:00
|
|
|
))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result, "Missing 'short_name' argument")
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict(
|
2016-07-12 20:46:55 +02:00
|
|
|
email='broken',
|
|
|
|
password='xxxx',
|
|
|
|
full_name='Romeo Montague',
|
|
|
|
short_name='Romeo',
|
2017-01-24 06:34:26 +01:00
|
|
|
))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result, "Bad name or username")
|
|
|
|
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", dict(
|
2016-07-12 20:46:55 +02:00
|
|
|
email='romeo@not-zulip.com',
|
|
|
|
password='xxxx',
|
|
|
|
full_name='Romeo Montague',
|
|
|
|
short_name='Romeo',
|
2017-01-24 06:34:26 +01:00
|
|
|
))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result,
|
2018-03-08 02:05:50 +01:00
|
|
|
"Email 'romeo@not-zulip.com' not allowed in this organization")
|
2016-07-12 20:46:55 +02:00
|
|
|
|
2017-03-31 16:20:07 +02:00
|
|
|
RealmDomain.objects.create(realm=get_realm('zulip'), domain='zulip.net')
|
2016-07-12 20:46:55 +02:00
|
|
|
valid_params = dict(
|
2016-09-19 23:13:13 +02:00
|
|
|
email='romeo@zulip.net',
|
2016-07-12 20:46:55 +02:00
|
|
|
password='xxxx',
|
|
|
|
full_name='Romeo Montague',
|
|
|
|
short_name='Romeo',
|
|
|
|
)
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", valid_params)
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
# Romeo is a newly registered user
|
|
|
|
new_user = get_user('romeo@zulip.net', get_realm('zulip'))
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assertEqual(new_user.full_name, 'Romeo Montague')
|
|
|
|
self.assertEqual(new_user.short_name, 'Romeo')
|
|
|
|
|
2018-03-05 20:19:07 +01:00
|
|
|
# we can't create the same user twice.
|
2016-12-31 08:07:22 +01:00
|
|
|
result = self.client_post("/json/users", valid_params)
|
2016-07-12 20:46:55 +02:00
|
|
|
self.assert_json_error(result,
|
2016-12-03 00:04:17 +01:00
|
|
|
"Email 'romeo@zulip.net' already in use")
|
2016-07-12 20:46:55 +02:00
|
|
|
|
2018-03-05 20:19:07 +01:00
|
|
|
# Don't allow user to sign up with disposable email.
|
2018-07-27 23:26:29 +02:00
|
|
|
realm.emails_restricted_to_domains = False
|
2018-03-05 20:19:07 +01:00
|
|
|
realm.disallow_disposable_email_addresses = True
|
|
|
|
realm.save()
|
|
|
|
|
|
|
|
valid_params["email"] = "abc@mailnator.com"
|
|
|
|
result = self.client_post("/json/users", valid_params)
|
2018-03-17 00:49:29 +01:00
|
|
|
self.assert_json_error(result, "Disposable email addresses are not allowed in this organization")
|
2018-03-05 20:19:07 +01:00
|
|
|
|
2018-06-20 13:08:07 +02:00
|
|
|
# Don't allow creating a user with + in their email address when realm
|
|
|
|
# is restricted to a domain.
|
2018-07-27 23:26:29 +02:00
|
|
|
realm.emails_restricted_to_domains = True
|
2018-06-20 13:08:07 +02:00
|
|
|
realm.save()
|
|
|
|
|
|
|
|
valid_params["email"] = "iago+label@zulip.com"
|
|
|
|
result = self.client_post("/json/users", valid_params)
|
|
|
|
self.assert_json_error(result, "Email addresses containing + are not allowed.")
|
|
|
|
|
|
|
|
# Users can be created with + in their email address when realm
|
|
|
|
# is not restricted to a domain.
|
2018-07-27 23:26:29 +02:00
|
|
|
realm.emails_restricted_to_domains = False
|
2018-06-20 13:08:07 +02:00
|
|
|
realm.save()
|
|
|
|
|
|
|
|
valid_params["email"] = "iago+label@zulip.com"
|
|
|
|
result = self.client_post("/json/users", valid_params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2017-05-07 17:21:26 +02:00
|
|
|
class UserProfileTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_emails_from_user_ids(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
othello = self.example_user('othello')
|
2013-10-20 21:10:03 +02:00
|
|
|
dct = get_emails_from_user_ids([hamlet.id, othello.id])
|
2017-05-25 01:40:26 +02:00
|
|
|
self.assertEqual(dct[hamlet.id], self.example_email("hamlet"))
|
2017-05-25 02:08:35 +02:00
|
|
|
self.assertEqual(dct[othello.id], self.example_email("othello"))
|
2013-10-20 21:10:03 +02:00
|
|
|
|
2018-05-08 13:54:40 +02:00
|
|
|
def test_valid_user_id(self) -> None:
|
|
|
|
realm = get_realm("zulip")
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
othello = self.example_user('othello')
|
|
|
|
bot = self.example_user("welcome_bot")
|
|
|
|
|
|
|
|
# Invalid user ID
|
2018-06-07 20:01:31 +02:00
|
|
|
invalid_uid = 1000 # type: Any
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, invalid_uid),
|
|
|
|
"User IDs is not a list")
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [invalid_uid]),
|
2018-05-08 13:54:40 +02:00
|
|
|
"Invalid user ID: %d" % (invalid_uid))
|
2018-06-07 20:01:31 +02:00
|
|
|
|
|
|
|
invalid_uid = "abc"
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [invalid_uid]),
|
|
|
|
"User IDs[0] is not an integer")
|
|
|
|
invalid_uid = str(othello.id)
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [invalid_uid]),
|
|
|
|
"User IDs[0] is not an integer")
|
2018-05-08 13:54:40 +02:00
|
|
|
|
|
|
|
# User is in different realm
|
2018-06-07 20:01:31 +02:00
|
|
|
self.assertEqual(check_valid_user_ids(get_realm("zephyr").id, [hamlet.id]),
|
2018-05-08 13:54:40 +02:00
|
|
|
"Invalid user ID: %d" % (hamlet.id))
|
|
|
|
|
|
|
|
# User is not active
|
|
|
|
hamlet.is_active = False
|
|
|
|
hamlet.save()
|
2018-06-07 20:01:31 +02:00
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [hamlet.id]),
|
|
|
|
"User with ID %d is deactivated" % (hamlet.id))
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [hamlet.id], allow_deactivated=True),
|
2018-05-08 13:54:40 +02:00
|
|
|
None)
|
|
|
|
|
2018-06-07 20:01:31 +02:00
|
|
|
# User is a bot
|
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [bot.id]),
|
|
|
|
"User with ID %d is a bot" % (bot.id))
|
2018-05-08 13:54:40 +02:00
|
|
|
|
|
|
|
# Succesfully get non-bot, active user belong to your realm
|
2018-06-07 20:01:31 +02:00
|
|
|
self.assertEqual(check_valid_user_ids(realm.id, [othello.id]), None)
|
2018-05-08 13:54:40 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_cache_invalidation(self) -> None:
|
2017-10-22 03:14:44 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
with mock.patch('zerver.lib.cache.delete_display_recipient_cache') as m:
|
|
|
|
hamlet.full_name = 'Hamlet Junior'
|
|
|
|
hamlet.save(update_fields=["full_name"])
|
|
|
|
|
|
|
|
self.assertTrue(m.called)
|
|
|
|
|
|
|
|
with mock.patch('zerver.lib.cache.delete_display_recipient_cache') as m:
|
|
|
|
hamlet.long_term_idle = True
|
|
|
|
hamlet.save(update_fields=["long_term_idle"])
|
|
|
|
|
|
|
|
self.assertFalse(m.called)
|
|
|
|
|
2017-11-01 10:04:16 +01:00
|
|
|
def test_user_ids_to_users(self) -> None:
|
|
|
|
real_user_ids = [
|
|
|
|
self.example_user('hamlet').id,
|
|
|
|
self.example_user('cordelia').id,
|
|
|
|
]
|
|
|
|
|
2018-04-05 01:31:30 +02:00
|
|
|
self.assertEqual(user_ids_to_users([], get_realm("zulip")), [])
|
|
|
|
self.assertEqual(set([user_profile.id for user_profile in user_ids_to_users(real_user_ids, get_realm("zulip"))]),
|
|
|
|
set(real_user_ids))
|
2017-11-01 10:04:16 +01:00
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
user_ids_to_users([1234], get_realm("zephyr"))
|
|
|
|
with self.assertRaises(JsonableError):
|
|
|
|
user_ids_to_users(real_user_ids, get_realm("zephyr"))
|
|
|
|
|
2017-11-16 02:28:50 +01:00
|
|
|
def test_bulk_get_users(self) -> None:
|
|
|
|
from zerver.lib.users import bulk_get_users
|
|
|
|
hamlet = self.example_email("hamlet")
|
|
|
|
cordelia = self.example_email("cordelia")
|
|
|
|
webhook_bot = self.example_email("webhook_bot")
|
|
|
|
result = bulk_get_users([hamlet, cordelia], get_realm("zulip"))
|
|
|
|
self.assertEqual(result[hamlet].email, hamlet)
|
|
|
|
self.assertEqual(result[cordelia].email, cordelia)
|
|
|
|
|
|
|
|
result = bulk_get_users([hamlet, cordelia, webhook_bot], None,
|
|
|
|
base_query=UserProfile.objects.all())
|
|
|
|
self.assertEqual(result[hamlet].email, hamlet)
|
|
|
|
self.assertEqual(result[cordelia].email, cordelia)
|
|
|
|
self.assertEqual(result[webhook_bot].email, webhook_bot)
|
|
|
|
|
2018-06-19 10:55:56 +02:00
|
|
|
def test_get_accounts_for_email(self) -> None:
|
|
|
|
def check_account_present_in_accounts(user: UserProfile, accounts: List[Dict[str, Optional[str]]]) -> None:
|
|
|
|
for account in accounts:
|
|
|
|
realm = user.realm
|
|
|
|
if account["avatar"] == avatar_url(user) and account["full_name"] == user.full_name \
|
|
|
|
and account["realm_name"] == realm.name and account["string_id"] == realm.string_id:
|
|
|
|
return
|
|
|
|
raise AssertionError("Account not found")
|
|
|
|
|
2018-05-18 16:17:03 +02:00
|
|
|
lear_realm = get_realm("lear")
|
2018-06-19 10:55:56 +02:00
|
|
|
cordelia_in_zulip = self.example_user("cordelia")
|
|
|
|
cordelia_in_lear = get_user("cordelia@zulip.com", lear_realm)
|
2018-05-18 16:17:03 +02:00
|
|
|
|
|
|
|
email = "cordelia@zulip.com"
|
2018-06-19 10:55:56 +02:00
|
|
|
accounts = get_accounts_for_email(email)
|
|
|
|
self.assert_length(accounts, 2)
|
|
|
|
check_account_present_in_accounts(cordelia_in_zulip, accounts)
|
|
|
|
check_account_present_in_accounts(cordelia_in_lear, accounts)
|
2018-05-18 16:17:03 +02:00
|
|
|
|
|
|
|
email = "CORDelia@zulip.com"
|
2018-06-19 10:55:56 +02:00
|
|
|
accounts = get_accounts_for_email(email)
|
|
|
|
self.assert_length(accounts, 2)
|
|
|
|
check_account_present_in_accounts(cordelia_in_zulip, accounts)
|
|
|
|
check_account_present_in_accounts(cordelia_in_lear, accounts)
|
2018-05-18 16:17:03 +02:00
|
|
|
|
|
|
|
email = "IAGO@ZULIP.COM"
|
2018-06-19 10:55:56 +02:00
|
|
|
accounts = get_accounts_for_email(email)
|
|
|
|
self.assert_length(accounts, 1)
|
|
|
|
check_account_present_in_accounts(self.example_user("iago"), accounts)
|
2018-05-18 16:17:03 +02:00
|
|
|
|
2018-05-18 19:54:50 +02:00
|
|
|
def test_get_source_profile(self) -> None:
|
|
|
|
iago = get_source_profile("iago@zulip.com", "zulip")
|
|
|
|
assert iago is not None
|
|
|
|
self.assertEqual(iago.email, "iago@zulip.com")
|
|
|
|
self.assertEqual(iago.realm, get_realm("zulip"))
|
|
|
|
|
|
|
|
iago = get_source_profile("IAGO@ZULIP.com", "zulip")
|
|
|
|
assert iago is not None
|
|
|
|
self.assertEqual(iago.email, "iago@zulip.com")
|
|
|
|
|
|
|
|
cordelia = get_source_profile("cordelia@zulip.com", "lear")
|
|
|
|
assert cordelia is not None
|
|
|
|
self.assertEqual(cordelia.email, "cordelia@zulip.com")
|
|
|
|
|
|
|
|
self.assertIsNone(get_source_profile("iagod@zulip.com", "zulip"))
|
|
|
|
self.assertIsNone(get_source_profile("iago@zulip.com", "ZULIP"))
|
|
|
|
self.assertIsNone(get_source_profile("iago@zulip.com", "lear"))
|
|
|
|
|
2018-05-21 19:30:26 +02:00
|
|
|
def test_copy_user_settings(self) -> None:
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
cordelia = self.example_user("cordelia")
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
|
|
|
|
cordelia.default_language = "de"
|
|
|
|
cordelia.emojiset = "apple"
|
|
|
|
cordelia.timezone = "America/Phoenix"
|
|
|
|
cordelia.night_mode = True
|
|
|
|
cordelia.enable_offline_email_notifications = False
|
|
|
|
cordelia.enable_stream_push_notifications = True
|
2018-06-13 20:16:51 +02:00
|
|
|
cordelia.enter_sends = False
|
2018-05-21 19:30:26 +02:00
|
|
|
cordelia.save()
|
|
|
|
|
2018-06-13 14:10:53 +02:00
|
|
|
UserHotspot.objects.filter(user=cordelia).delete()
|
|
|
|
UserHotspot.objects.filter(user=iago).delete()
|
|
|
|
hotspots_completed = ['intro_reply', 'intro_streams', 'intro_topics']
|
|
|
|
for hotspot in hotspots_completed:
|
|
|
|
UserHotspot.objects.create(user=cordelia, hotspot=hotspot)
|
|
|
|
|
2018-05-23 20:35:01 +02:00
|
|
|
copy_user_settings(cordelia, iago)
|
2018-05-21 19:30:26 +02:00
|
|
|
|
|
|
|
# We verify that cordelia and iago match, but hamlet has the defaults.
|
2018-05-25 19:24:30 +02:00
|
|
|
self.assertEqual(iago.full_name, "Cordelia Lear")
|
|
|
|
self.assertEqual(cordelia.full_name, "Cordelia Lear")
|
|
|
|
self.assertEqual(hamlet.full_name, "King Hamlet")
|
|
|
|
|
2018-05-21 19:30:26 +02:00
|
|
|
self.assertEqual(iago.default_language, "de")
|
|
|
|
self.assertEqual(cordelia.default_language, "de")
|
|
|
|
self.assertEqual(hamlet.default_language, "en")
|
|
|
|
|
|
|
|
self.assertEqual(iago.emojiset, "apple")
|
|
|
|
self.assertEqual(cordelia.emojiset, "apple")
|
2018-08-25 09:18:49 +02:00
|
|
|
self.assertEqual(hamlet.emojiset, "google-blob")
|
2018-05-21 19:30:26 +02:00
|
|
|
|
|
|
|
self.assertEqual(iago.timezone, "America/Phoenix")
|
|
|
|
self.assertEqual(cordelia.timezone, "America/Phoenix")
|
|
|
|
self.assertEqual(hamlet.timezone, "")
|
|
|
|
|
|
|
|
self.assertEqual(iago.night_mode, True)
|
|
|
|
self.assertEqual(cordelia.night_mode, True)
|
|
|
|
self.assertEqual(hamlet.night_mode, False)
|
|
|
|
|
|
|
|
self.assertEqual(iago.enable_offline_email_notifications, False)
|
|
|
|
self.assertEqual(cordelia.enable_offline_email_notifications, False)
|
|
|
|
self.assertEqual(hamlet.enable_offline_email_notifications, True)
|
|
|
|
|
|
|
|
self.assertEqual(iago.enable_stream_push_notifications, True)
|
|
|
|
self.assertEqual(cordelia.enable_stream_push_notifications, True)
|
|
|
|
self.assertEqual(hamlet.enable_stream_push_notifications, False)
|
|
|
|
|
2018-06-13 20:16:51 +02:00
|
|
|
self.assertEqual(iago.enter_sends, False)
|
|
|
|
self.assertEqual(cordelia.enter_sends, False)
|
|
|
|
self.assertEqual(hamlet.enter_sends, True)
|
|
|
|
|
2018-06-13 14:10:53 +02:00
|
|
|
hotspots = list(UserHotspot.objects.filter(user=iago).values_list('hotspot', flat=True))
|
|
|
|
self.assertEqual(hotspots, hotspots_completed)
|
|
|
|
|
2018-09-01 22:39:29 +02:00
|
|
|
def test_get_user_by_id_in_realm_including_cross_realm(self) -> None:
|
|
|
|
realm = get_realm('zulip')
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
othello = self.example_user('othello')
|
|
|
|
bot = self.example_user('welcome_bot')
|
|
|
|
|
|
|
|
# Pass in the ID of a cross-realm bot and a valid realm
|
|
|
|
cross_realm_bot = get_user_by_id_in_realm_including_cross_realm(
|
|
|
|
bot.id, realm)
|
|
|
|
self.assertEqual(cross_realm_bot.email, bot.email)
|
|
|
|
self.assertEqual(cross_realm_bot.id, bot.id)
|
|
|
|
|
|
|
|
# Pass in the ID of a cross-realm bot but with a invalid realm,
|
|
|
|
# note that the realm should be irrelevant here
|
|
|
|
cross_realm_bot = get_user_by_id_in_realm_including_cross_realm(
|
|
|
|
bot.id, get_realm('invalid'))
|
|
|
|
self.assertEqual(cross_realm_bot.email, bot.email)
|
|
|
|
self.assertEqual(cross_realm_bot.id, bot.id)
|
|
|
|
|
|
|
|
# Pass in the ID of a non-cross-realm user with a realm
|
|
|
|
user_profile = get_user_by_id_in_realm_including_cross_realm(
|
|
|
|
othello.id, realm)
|
|
|
|
self.assertEqual(user_profile.email, othello.email)
|
|
|
|
self.assertEqual(user_profile.id, othello.id)
|
|
|
|
|
|
|
|
# If the realm doesn't match, or if the ID is not that of a
|
|
|
|
# cross-realm bot, UserProfile.DoesNotExist is raised
|
|
|
|
with self.assertRaises(UserProfile.DoesNotExist):
|
|
|
|
get_user_by_id_in_realm_including_cross_realm(
|
|
|
|
hamlet.id, get_realm('invalid'))
|
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class ActivateTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_basics(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
user = self.example_user('hamlet')
|
2013-11-16 17:11:15 +01:00
|
|
|
do_deactivate_user(user)
|
2013-11-15 18:57:44 +01:00
|
|
|
self.assertFalse(user.is_active)
|
2013-11-16 17:11:15 +01:00
|
|
|
do_reactivate_user(user)
|
2013-11-15 18:57:44 +01:00
|
|
|
self.assertTrue(user.is_active)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
admin = self.example_user('othello')
|
2014-01-22 20:12:29 +01:00
|
|
|
do_change_is_admin(admin, True)
|
2017-05-25 02:08:35 +02:00
|
|
|
self.login(self.example_email("othello"))
|
2013-11-15 19:39:03 +01:00
|
|
|
|
2017-05-07 17:21:26 +02:00
|
|
|
user = self.example_user('hamlet')
|
2013-11-15 19:39:03 +01:00
|
|
|
self.assertTrue(user.is_active)
|
|
|
|
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_delete('/json/users/{}'.format(user.id))
|
2013-11-15 19:39:03 +01:00
|
|
|
self.assert_json_success(result)
|
2017-05-07 17:21:26 +02:00
|
|
|
user = self.example_user('hamlet')
|
2013-11-15 19:39:03 +01:00
|
|
|
self.assertFalse(user.is_active)
|
|
|
|
|
2018-05-17 19:45:13 +02:00
|
|
|
result = self.client_post('/json/users/{}/reactivate'.format(user.id))
|
2013-11-15 19:39:03 +01:00
|
|
|
self.assert_json_success(result)
|
2017-05-07 17:21:26 +02:00
|
|
|
user = self.example_user('hamlet')
|
2013-11-15 19:39:03 +01:00
|
|
|
self.assertTrue(user.is_active)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_with_nonexistent_user(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
admin = self.example_user('othello')
|
2016-07-13 05:24:11 +02:00
|
|
|
do_change_is_admin(admin, True)
|
2017-05-25 02:08:35 +02:00
|
|
|
self.login(self.example_email("othello"))
|
2016-07-13 05:24:11 +02:00
|
|
|
|
2018-04-03 00:36:31 +02:00
|
|
|
# Cannot deactivate a user with the bot api
|
2018-05-15 15:26:04 +02:00
|
|
|
result = self.client_delete('/json/bots/{}'.format(self.example_user("hamlet").id))
|
2014-02-11 17:14:33 +01:00
|
|
|
self.assert_json_error(result, 'No such bot')
|
|
|
|
|
2018-04-03 00:36:31 +02:00
|
|
|
# Cannot deactivate a nonexistent user.
|
2018-05-17 19:36:33 +02:00
|
|
|
invalid_user_id = 1000
|
|
|
|
result = self.client_delete('/json/users/{}'.format(invalid_user_id))
|
2016-07-13 05:24:11 +02:00
|
|
|
self.assert_json_error(result, 'No such user')
|
|
|
|
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_delete('/json/users/{}'.format(self.example_user("webhook_bot").id))
|
2018-05-15 15:26:04 +02:00
|
|
|
self.assert_json_error(result, 'No such user')
|
|
|
|
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_delete('/json/users/{}'.format(self.example_user("iago").id))
|
2016-12-05 06:40:00 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_delete('/json/users/{}'.format(admin.id))
|
2016-12-05 06:40:00 +01:00
|
|
|
self.assert_json_error(result, 'Cannot deactivate the only organization administrator')
|
|
|
|
|
2018-04-03 00:36:31 +02:00
|
|
|
# Cannot reactivate a nonexistent user.
|
2018-05-17 19:45:13 +02:00
|
|
|
invalid_user_id = 1000
|
|
|
|
result = self.client_post('/json/users/{}/reactivate'.format(invalid_user_id))
|
2016-07-13 05:24:11 +02:00
|
|
|
self.assert_json_error(result, 'No such user')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_with_insufficient_permissions(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
non_admin = self.example_user('othello')
|
2016-07-13 05:42:29 +02:00
|
|
|
do_change_is_admin(non_admin, False)
|
2017-05-25 02:08:35 +02:00
|
|
|
self.login(self.example_email("othello"))
|
2016-07-13 05:42:29 +02:00
|
|
|
|
2018-04-03 00:36:31 +02:00
|
|
|
# Cannot deactivate a user with the users api
|
2018-05-17 19:36:33 +02:00
|
|
|
result = self.client_delete('/json/users/{}'.format(self.example_user("hamlet").id))
|
2016-07-13 05:42:29 +02:00
|
|
|
self.assert_json_error(result, 'Insufficient permission')
|
|
|
|
|
2018-04-03 00:36:31 +02:00
|
|
|
# Cannot reactivate a user
|
2018-05-17 19:45:13 +02:00
|
|
|
result = self.client_post('/json/users/{}/reactivate'.format(self.example_user("hamlet").id))
|
2016-07-13 05:42:29 +02:00
|
|
|
self.assert_json_error(result, 'Insufficient permission')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_clear_scheduled_jobs(self) -> None:
|
2017-07-01 03:56:40 +02:00
|
|
|
user = self.example_user('hamlet')
|
2017-12-05 03:19:48 +01:00
|
|
|
send_future_email('zerver/emails/followup_day1', user.realm,
|
|
|
|
to_user_id=user.id, delay=datetime.timedelta(hours=1))
|
2017-07-02 21:10:41 +02:00
|
|
|
self.assertEqual(ScheduledEmail.objects.count(), 1)
|
2017-07-01 03:56:40 +02:00
|
|
|
do_deactivate_user(user)
|
2017-07-02 21:10:41 +02:00
|
|
|
self.assertEqual(ScheduledEmail.objects.count(), 0)
|
2017-07-01 03:56:40 +02:00
|
|
|
|
2017-10-23 22:03:28 +02:00
|
|
|
class RecipientInfoTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_stream_recipient_info(self) -> None:
|
2017-10-23 22:03:28 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
cordelia = self.example_user('cordelia')
|
|
|
|
othello = self.example_user('othello')
|
|
|
|
|
|
|
|
realm = hamlet.realm
|
|
|
|
|
|
|
|
stream_name = 'Test Stream'
|
2017-10-24 00:07:03 +02:00
|
|
|
topic_name = 'test topic'
|
2017-10-23 22:03:28 +02:00
|
|
|
|
|
|
|
for user in [hamlet, cordelia, othello]:
|
|
|
|
self.subscribe(user, stream_name)
|
|
|
|
|
|
|
|
stream = get_stream(stream_name, realm)
|
2017-10-28 20:26:11 +02:00
|
|
|
recipient = get_stream_recipient(stream.id)
|
2017-10-23 22:03:28 +02:00
|
|
|
|
2017-10-24 00:07:03 +02:00
|
|
|
stream_topic = StreamTopicTarget(
|
|
|
|
stream_id=stream.id,
|
|
|
|
topic_name=topic_name,
|
|
|
|
)
|
|
|
|
|
2017-10-23 22:03:28 +02:00
|
|
|
sub = get_subscription(stream_name, hamlet)
|
|
|
|
sub.push_notifications = True
|
|
|
|
sub.save()
|
|
|
|
|
|
|
|
info = get_recipient_info(
|
|
|
|
recipient=recipient,
|
|
|
|
sender_id=hamlet.id,
|
2017-10-24 00:07:03 +02:00
|
|
|
stream_topic=stream_topic,
|
2017-10-23 22:03:28 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
all_user_ids = {hamlet.id, cordelia.id, othello.id}
|
|
|
|
|
|
|
|
expected_info = dict(
|
|
|
|
active_user_ids=all_user_ids,
|
|
|
|
push_notify_user_ids=set(),
|
|
|
|
stream_push_user_ids={hamlet.id},
|
2018-07-12 11:33:51 +02:00
|
|
|
stream_email_user_ids=set(),
|
2017-10-23 22:03:28 +02:00
|
|
|
um_eligible_user_ids=all_user_ids,
|
|
|
|
long_term_idle_user_ids=set(),
|
2017-10-24 20:08:19 +02:00
|
|
|
default_bot_user_ids=set(),
|
2017-10-23 22:03:28 +02:00
|
|
|
service_bot_tuples=[],
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(info, expected_info)
|
|
|
|
|
2017-10-24 00:07:03 +02:00
|
|
|
# Now mute Hamlet to omit him from stream_push_user_ids.
|
|
|
|
add_topic_mute(
|
|
|
|
user_profile=hamlet,
|
|
|
|
stream_id=stream.id,
|
|
|
|
recipient_id=recipient.id,
|
|
|
|
topic_name=topic_name,
|
|
|
|
)
|
|
|
|
|
|
|
|
info = get_recipient_info(
|
|
|
|
recipient=recipient,
|
|
|
|
sender_id=hamlet.id,
|
|
|
|
stream_topic=stream_topic,
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(info['stream_push_user_ids'], set())
|
|
|
|
|
2017-10-24 19:25:50 +02:00
|
|
|
# Add a service bot.
|
|
|
|
service_bot = do_create_user(
|
|
|
|
email='service-bot@zulip.com',
|
|
|
|
password='',
|
|
|
|
realm=realm,
|
|
|
|
full_name='',
|
|
|
|
short_name='',
|
|
|
|
bot_type=UserProfile.EMBEDDED_BOT,
|
|
|
|
)
|
|
|
|
|
|
|
|
info = get_recipient_info(
|
|
|
|
recipient=recipient,
|
|
|
|
sender_id=hamlet.id,
|
|
|
|
stream_topic=stream_topic,
|
|
|
|
possibly_mentioned_user_ids={service_bot.id}
|
|
|
|
)
|
|
|
|
self.assertEqual(info['service_bot_tuples'], [
|
|
|
|
(service_bot.id, UserProfile.EMBEDDED_BOT),
|
|
|
|
])
|
|
|
|
|
2017-10-24 20:08:19 +02:00
|
|
|
# Add a normal bot.
|
|
|
|
normal_bot = do_create_user(
|
|
|
|
email='normal-bot@zulip.com',
|
|
|
|
password='',
|
|
|
|
realm=realm,
|
|
|
|
full_name='',
|
|
|
|
short_name='',
|
|
|
|
bot_type=UserProfile.DEFAULT_BOT,
|
|
|
|
)
|
|
|
|
|
|
|
|
info = get_recipient_info(
|
|
|
|
recipient=recipient,
|
|
|
|
sender_id=hamlet.id,
|
|
|
|
stream_topic=stream_topic,
|
|
|
|
possibly_mentioned_user_ids={service_bot.id, normal_bot.id}
|
|
|
|
)
|
|
|
|
self.assertEqual(info['default_bot_user_ids'], {normal_bot.id})
|
|
|
|
|
2018-05-16 03:07:36 +02:00
|
|
|
def test_get_recipient_info_invalid_recipient_type(self) -> None:
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
realm = hamlet.realm
|
|
|
|
|
|
|
|
stream = get_stream('Rome', realm)
|
|
|
|
stream_topic = StreamTopicTarget(
|
|
|
|
stream_id=stream.id,
|
|
|
|
topic_name='test topic',
|
|
|
|
)
|
|
|
|
|
|
|
|
# Make sure get_recipient_info asserts on invalid recipient types
|
|
|
|
with self.assertRaisesRegex(ValueError, 'Bad recipient type'):
|
2018-05-16 05:07:33 +02:00
|
|
|
invalid_recipient = Recipient(type=999) # 999 is not a valid type
|
|
|
|
get_recipient_info(
|
2018-05-16 03:07:36 +02:00
|
|
|
recipient=invalid_recipient,
|
|
|
|
sender_id=hamlet.id,
|
|
|
|
stream_topic=stream_topic,
|
|
|
|
)
|
|
|
|
|
2017-10-10 04:51:04 +02:00
|
|
|
class BulkUsersTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_client_gravatar_option(self) -> None:
|
2017-10-10 04:51:04 +02:00
|
|
|
self.login(self.example_email('cordelia'))
|
|
|
|
|
|
|
|
hamlet = self.example_user('hamlet')
|
|
|
|
|
2018-05-11 01:39:38 +02:00
|
|
|
def get_hamlet_avatar(client_gravatar: bool) -> Optional[str]:
|
2017-10-10 04:51:04 +02:00
|
|
|
data = dict(client_gravatar=ujson.dumps(client_gravatar))
|
|
|
|
result = self.client_get('/json/users', data)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
rows = result.json()['members']
|
|
|
|
hamlet_data = [
|
|
|
|
row for row in rows
|
|
|
|
if row['user_id'] == hamlet.id
|
|
|
|
][0]
|
|
|
|
return hamlet_data['avatar_url']
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
get_hamlet_avatar(client_gravatar=True),
|
|
|
|
None
|
|
|
|
)
|
|
|
|
|
|
|
|
'''
|
|
|
|
The main purpose of this test is to make sure we
|
|
|
|
return None for avatar_url when client_gravatar is
|
|
|
|
set to True. And we do a sanity check for when it's
|
|
|
|
False, but we leave it to other tests to validate
|
|
|
|
the specific URL.
|
|
|
|
'''
|
|
|
|
self.assertIn(
|
|
|
|
'gravatar.com',
|
|
|
|
get_hamlet_avatar(client_gravatar=False),
|
|
|
|
)
|
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class GetProfileTest(ZulipTestCase):
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2018-05-11 01:39:38 +02:00
|
|
|
def common_update_pointer(self, email: str, pointer: int) -> None:
|
2013-01-22 20:07:51 +01:00
|
|
|
self.login(email)
|
2016-12-31 08:54:00 +01:00
|
|
|
result = self.client_post("/json/users/me/pointer", {"pointer": pointer})
|
2013-01-22 20:07:51 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2018-05-11 01:39:38 +02:00
|
|
|
def common_get_profile(self, user_id: str) -> Dict[str, Any]:
|
2017-05-24 02:42:31 +02:00
|
|
|
# Assumes all users are example users in realm 'zulip'
|
|
|
|
user_profile = self.example_user(user_id)
|
2017-10-28 18:43:23 +02:00
|
|
|
self.send_stream_message(user_profile.email, "Verona", "hello")
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2017-12-14 19:02:31 +01:00
|
|
|
result = self.api_get(user_profile.email, "/api/v1/users/me")
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2013-07-02 16:15:10 +02:00
|
|
|
max_id = most_recent_message(user_profile).id
|
2013-01-22 20:07:51 +01:00
|
|
|
|
|
|
|
self.assert_json_success(result)
|
2017-08-17 08:46:17 +02:00
|
|
|
json = result.json()
|
2013-01-22 20:07:51 +01:00
|
|
|
|
|
|
|
self.assertIn("client_id", json)
|
|
|
|
self.assertIn("max_message_id", json)
|
|
|
|
self.assertIn("pointer", json)
|
|
|
|
|
2013-01-17 18:12:02 +01:00
|
|
|
self.assertEqual(json["max_message_id"], max_id)
|
2013-01-22 20:07:51 +01:00
|
|
|
return json
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_pointer(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
email = self.example_email("hamlet")
|
2016-09-14 02:14:45 +02:00
|
|
|
self.login(email)
|
|
|
|
result = self.client_get("/json/users/me/pointer")
|
|
|
|
self.assert_json_success(result)
|
2017-08-16 09:52:46 +02:00
|
|
|
self.assertIn("pointer", result.json())
|
2016-09-14 02:14:45 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_cache_behavior(self) -> None:
|
2017-07-12 21:59:19 +02:00
|
|
|
"""Tests whether fetching a user object the normal way, with
|
|
|
|
`get_user`, makes 1 cache query and 1 database query.
|
|
|
|
"""
|
|
|
|
realm = get_realm("zulip")
|
|
|
|
email = self.example_email("hamlet")
|
2013-09-28 01:05:08 +02:00
|
|
|
with queries_captured() as queries:
|
|
|
|
with simulated_empty_cache() as cache_queries:
|
2017-07-12 21:59:19 +02:00
|
|
|
user_profile = get_user(email, realm)
|
2013-09-28 01:05:08 +02:00
|
|
|
|
2017-03-31 11:08:45 +02:00
|
|
|
self.assert_length(queries, 1)
|
2016-09-25 21:30:10 +02:00
|
|
|
self.assert_length(cache_queries, 1)
|
2017-07-12 21:59:19 +02:00
|
|
|
self.assertEqual(user_profile.email, email)
|
2013-09-28 01:05:08 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_user_profile(self) -> None:
|
2017-05-25 01:40:26 +02:00
|
|
|
self.login(self.example_email("hamlet"))
|
2016-12-13 19:17:49 +01:00
|
|
|
result = ujson.loads(self.client_get('/json/users/me').content)
|
|
|
|
self.assertEqual(result['short_name'], 'hamlet')
|
2017-05-25 01:40:26 +02:00
|
|
|
self.assertEqual(result['email'], self.example_email("hamlet"))
|
2016-12-13 19:17:49 +01:00
|
|
|
self.assertEqual(result['full_name'], 'King Hamlet')
|
|
|
|
self.assertIn("user_id", result)
|
|
|
|
self.assertFalse(result['is_bot'])
|
|
|
|
self.assertFalse(result['is_admin'])
|
2017-05-25 01:44:04 +02:00
|
|
|
self.login(self.example_email("iago"))
|
2016-12-13 19:17:49 +01:00
|
|
|
result = ujson.loads(self.client_get('/json/users/me').content)
|
|
|
|
self.assertEqual(result['short_name'], 'iago')
|
2017-05-25 01:44:04 +02:00
|
|
|
self.assertEqual(result['email'], self.example_email("iago"))
|
2016-12-13 19:17:49 +01:00
|
|
|
self.assertEqual(result['full_name'], 'Iago')
|
|
|
|
self.assertFalse(result['is_bot'])
|
|
|
|
self.assertTrue(result['is_admin'])
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_get_empty_profile(self) -> None:
|
2013-01-22 20:07:51 +01:00
|
|
|
"""
|
2016-04-02 20:07:28 +02:00
|
|
|
Ensure GET /users/me returns a max message id and returns successfully
|
2013-01-22 20:07:51 +01:00
|
|
|
"""
|
2017-05-24 02:42:31 +02:00
|
|
|
json = self.common_get_profile("othello")
|
2013-01-17 18:12:02 +01:00
|
|
|
self.assertEqual(json["pointer"], -1)
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_profile_with_pointer(self) -> None:
|
2013-01-22 20:07:51 +01:00
|
|
|
"""
|
2016-04-02 20:07:28 +02:00
|
|
|
Ensure GET /users/me returns a proper pointer id after the pointer is updated
|
2013-01-22 20:07:51 +01:00
|
|
|
"""
|
2013-08-19 21:05:23 +02:00
|
|
|
|
2017-10-28 18:43:23 +02:00
|
|
|
id1 = self.send_stream_message(self.example_email("othello"), "Verona")
|
|
|
|
id2 = self.send_stream_message(self.example_email("othello"), "Verona")
|
2013-08-19 21:05:23 +02:00
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
json = self.common_get_profile("hamlet")
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
self.common_update_pointer(self.example_email("hamlet"), id2)
|
|
|
|
json = self.common_get_profile("hamlet")
|
2013-08-19 21:05:23 +02:00
|
|
|
self.assertEqual(json["pointer"], id2)
|
2013-01-22 20:07:51 +01:00
|
|
|
|
2017-05-24 02:42:31 +02:00
|
|
|
self.common_update_pointer(self.example_email("hamlet"), id1)
|
|
|
|
json = self.common_get_profile("hamlet")
|
2017-05-07 20:04:04 +02:00
|
|
|
self.assertEqual(json["pointer"], id2) # pointer does not move backwards
|
2013-08-19 21:05:23 +02:00
|
|
|
|
2016-12-31 08:54:00 +01:00
|
|
|
result = self.client_post("/json/users/me/pointer", {"pointer": 99999999})
|
2013-08-19 21:05:23 +02:00
|
|
|
self.assert_json_error(result, "Invalid message ID")
|
2012-12-19 20:19:46 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_all_profiles_avatar_urls(self) -> None:
|
2017-05-07 17:21:26 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2017-12-14 19:02:31 +01:00
|
|
|
result = self.api_get(self.example_email("hamlet"), "/api/v1/users")
|
2014-07-18 06:16:14 +02:00
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2017-08-16 09:52:46 +02:00
|
|
|
for user in result.json()['members']:
|
2017-05-25 01:40:26 +02:00
|
|
|
if user['email'] == self.example_email("hamlet"):
|
2014-07-18 06:16:14 +02:00
|
|
|
self.assertEqual(
|
|
|
|
user['avatar_url'],
|
2017-02-16 22:35:57 +01:00
|
|
|
avatar_url(user_profile),
|
2014-07-18 06:16:14 +02:00
|
|
|
)
|