2014-01-31 21:08:40 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
2015-11-01 17:15:05 +01:00
|
|
|
from __future__ import absolute_import
|
2016-12-01 08:54:21 +01:00
|
|
|
import datetime
|
2014-07-03 18:18:00 +02:00
|
|
|
from django.conf import settings
|
2016-06-04 20:14:05 +02:00
|
|
|
from django.http import HttpResponse
|
2014-01-31 21:08:40 +01:00
|
|
|
from django.test import TestCase
|
|
|
|
|
2016-10-31 12:18:13 +01:00
|
|
|
from mock import patch
|
2016-12-13 10:59:54 +01:00
|
|
|
from zerver.lib.test_helpers import MockLDAP
|
2016-10-31 12:18:13 +01:00
|
|
|
|
2016-12-01 08:54:21 +01:00
|
|
|
from confirmation.models import Confirmation
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
from zilencer.models import Deployment
|
|
|
|
|
2016-12-24 04:35:58 +01:00
|
|
|
from zerver.forms import HomepageForm
|
2017-01-07 21:46:03 +01:00
|
|
|
from zerver.lib.actions import do_change_password
|
2016-10-12 05:13:32 +02:00
|
|
|
from zerver.views.invite import get_invitee_emails_set
|
2014-01-31 21:08:40 +01:00
|
|
|
from zerver.models import (
|
2017-01-04 05:30:48 +01:00
|
|
|
get_realm, get_prereg_user_by_email, get_user_profile_by_email,
|
2016-11-24 20:26:55 +01:00
|
|
|
PreregistrationUser, Realm, RealmAlias, Recipient,
|
|
|
|
Referral, ScheduledJob, UserProfile, UserMessage,
|
2016-12-01 08:54:21 +01:00
|
|
|
Stream, Subscription, ScheduledJob
|
2014-01-31 21:08:40 +01:00
|
|
|
)
|
2016-12-01 08:54:21 +01:00
|
|
|
from zerver.management.commands.deliver_email import send_email_job
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
from zerver.lib.actions import (
|
|
|
|
set_default_streams,
|
2017-02-27 00:29:33 +01:00
|
|
|
do_change_is_admin,
|
|
|
|
get_stream
|
2014-01-31 21:08:40 +01:00
|
|
|
)
|
|
|
|
|
2016-09-13 22:49:03 +02:00
|
|
|
from zerver.lib.initial_password import initial_password
|
2016-11-11 05:33:30 +01:00
|
|
|
from zerver.lib.actions import do_deactivate_realm, do_set_realm_default_language, \
|
|
|
|
add_new_user_history
|
2014-01-31 21:08:40 +01:00
|
|
|
from zerver.lib.digest import send_digest_email
|
2016-12-01 08:54:21 +01:00
|
|
|
from zerver.lib.notifications import (
|
|
|
|
enqueue_welcome_emails, one_click_unsubscribe_link, send_local_email_template_with_delay)
|
2017-02-12 21:21:31 +01:00
|
|
|
from zerver.lib.test_helpers import find_pattern_in_email, find_key_by_email, queries_captured, \
|
2016-11-09 00:47:27 +01:00
|
|
|
HostRequestMock
|
2016-11-10 19:30:09 +01:00
|
|
|
from zerver.lib.test_classes import (
|
|
|
|
ZulipTestCase,
|
|
|
|
)
|
2014-01-31 21:08:40 +01:00
|
|
|
from zerver.lib.test_runner import slow
|
2015-08-19 20:53:55 +02:00
|
|
|
from zerver.lib.session_user import get_session_dict_user
|
2016-12-01 08:54:21 +01:00
|
|
|
from zerver.context_processors import common_context
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
import re
|
|
|
|
import ujson
|
|
|
|
|
2017-02-12 21:21:31 +01:00
|
|
|
from typing import Set, Optional
|
|
|
|
|
2016-01-24 03:39:44 +01:00
|
|
|
from six.moves import urllib
|
2015-11-01 17:15:05 +01:00
|
|
|
from six.moves import range
|
2016-03-11 10:57:29 +01:00
|
|
|
import six
|
2016-12-04 18:38:56 +01:00
|
|
|
from typing import Any, Text
|
2016-12-07 10:23:36 +01:00
|
|
|
import os
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class PublicURLTest(ZulipTestCase):
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Account creation URLs are accessible even when not logged in. Authenticated
|
|
|
|
URLs redirect to a page.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def fetch(self, method, urls, expected_status):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: (str, List[str], int) -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
for url in urls:
|
2016-12-16 05:58:46 +01:00
|
|
|
# e.g. self.client_post(url) if method is "post"
|
|
|
|
response = getattr(self, method)(url)
|
2014-01-31 21:08:40 +01:00
|
|
|
self.assertEqual(response.status_code, expected_status,
|
|
|
|
msg="Expected %d, received %d for %s to %s" % (
|
2016-12-02 08:15:16 +01:00
|
|
|
expected_status, response.status_code, method, url))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_public_urls(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Test which views are accessible when not logged in.
|
|
|
|
"""
|
|
|
|
# FIXME: We should also test the Tornado URLs -- this codepath
|
|
|
|
# can't do so because this Django test mechanism doesn't go
|
|
|
|
# through Tornado.
|
2016-12-30 11:42:59 +01:00
|
|
|
denmark_stream_id = Stream.objects.get(name='Denmark').id
|
2016-10-16 20:26:01 +02:00
|
|
|
get_urls = {200: ["/accounts/home/", "/accounts/login/"
|
|
|
|
"/en/accounts/home/", "/ru/accounts/home/",
|
2016-11-09 01:45:36 +01:00
|
|
|
"/en/accounts/login/", "/ru/accounts/login/",
|
|
|
|
"/help/"],
|
2016-10-16 20:26:01 +02:00
|
|
|
302: ["/", "/en/", "/ru/"],
|
2016-12-30 11:42:59 +01:00
|
|
|
401: ["/json/streams/%d/members" % (denmark_stream_id,),
|
2014-01-31 21:08:40 +01:00
|
|
|
"/api/v1/users/me/subscriptions",
|
|
|
|
"/api/v1/messages",
|
2016-04-01 21:57:42 +02:00
|
|
|
"/json/messages",
|
2016-10-25 22:45:39 +02:00
|
|
|
"/api/v1/streams",
|
2014-01-31 21:08:40 +01:00
|
|
|
],
|
2016-11-30 21:55:59 +01:00
|
|
|
404: ["/help/nonexistent"],
|
2016-12-01 06:16:45 +01:00
|
|
|
}
|
2016-12-07 10:23:36 +01:00
|
|
|
|
|
|
|
# Add all files in 'templates/zerver/help' directory (except for 'main.html' and
|
|
|
|
# 'index.md') to `get_urls['200']` list.
|
|
|
|
for doc in os.listdir('./templates/zerver/help'):
|
2017-01-30 20:54:40 +01:00
|
|
|
if doc.startswith(".") or '~' in doc or '#' in doc:
|
|
|
|
continue
|
2016-12-31 02:46:38 +01:00
|
|
|
if doc not in {'main.html', 'index.md', 'include'}:
|
2016-12-07 10:23:36 +01:00
|
|
|
get_urls[200].append('/help/' + os.path.splitext(doc)[0]) # Strip the extension.
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
post_urls = {200: ["/accounts/login/"],
|
|
|
|
302: ["/accounts/logout/"],
|
2016-04-17 14:47:12 +02:00
|
|
|
401: ["/json/messages",
|
2014-01-31 21:08:40 +01:00
|
|
|
"/json/invite_users",
|
|
|
|
"/json/settings/change",
|
|
|
|
"/json/subscriptions/exists",
|
|
|
|
"/json/subscriptions/property",
|
|
|
|
"/json/fetch_api_key",
|
2016-12-31 08:54:00 +01:00
|
|
|
"/json/users/me/pointer",
|
2015-11-30 21:39:40 +01:00
|
|
|
"/json/users/me/subscriptions",
|
2014-01-31 21:08:40 +01:00
|
|
|
"/api/v1/users/me/subscriptions",
|
|
|
|
],
|
2016-09-27 21:41:42 +02:00
|
|
|
400: ["/api/v1/external/github",
|
2014-01-31 21:08:40 +01:00
|
|
|
"/api/v1/fetch_api_key",
|
|
|
|
],
|
2016-12-01 06:16:45 +01:00
|
|
|
}
|
2016-04-02 20:24:19 +02:00
|
|
|
put_urls = {401: ["/json/users/me/pointer"],
|
2016-12-01 06:16:45 +01:00
|
|
|
}
|
2016-03-11 10:57:29 +01:00
|
|
|
for status_code, url_set in six.iteritems(get_urls):
|
2016-12-16 05:58:46 +01:00
|
|
|
self.fetch("client_get", url_set, status_code)
|
2016-03-11 10:57:29 +01:00
|
|
|
for status_code, url_set in six.iteritems(post_urls):
|
2016-12-16 05:58:46 +01:00
|
|
|
self.fetch("client_post", url_set, status_code)
|
2016-04-02 20:24:19 +02:00
|
|
|
for status_code, url_set in six.iteritems(put_urls):
|
2016-12-16 05:58:46 +01:00
|
|
|
self.fetch("client_put", url_set, status_code)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2015-10-02 13:23:26 +02:00
|
|
|
def test_get_gcid_when_not_configured(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2015-10-02 13:23:26 +02:00
|
|
|
with self.settings(GOOGLE_CLIENT_ID=None):
|
2016-07-28 00:38:45 +02:00
|
|
|
resp = self.client_get("/api/v1/fetch_google_client_id")
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(400, resp.status_code,
|
2016-12-16 05:51:27 +01:00
|
|
|
msg="Expected 400, received %d for GET /api/v1/fetch_google_client_id" % (
|
|
|
|
resp.status_code,))
|
2015-10-02 13:23:26 +02:00
|
|
|
data = ujson.loads(resp.content)
|
|
|
|
self.assertEqual('error', data['result'])
|
|
|
|
|
|
|
|
def test_get_gcid_when_configured(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2015-10-02 13:23:26 +02:00
|
|
|
with self.settings(GOOGLE_CLIENT_ID="ABCD"):
|
2016-07-28 00:38:45 +02:00
|
|
|
resp = self.client_get("/api/v1/fetch_google_client_id")
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(200, resp.status_code,
|
2016-12-16 05:51:27 +01:00
|
|
|
msg="Expected 200, received %d for GET /api/v1/fetch_google_client_id" % (
|
|
|
|
resp.status_code,))
|
2015-10-02 13:23:26 +02:00
|
|
|
data = ujson.loads(resp.content)
|
|
|
|
self.assertEqual('success', data['result'])
|
|
|
|
self.assertEqual('ABCD', data['google_client_id'])
|
|
|
|
|
2016-11-11 05:33:30 +01:00
|
|
|
class AddNewUserHistoryTest(ZulipTestCase):
|
|
|
|
def test_add_new_user_history_race(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""Sends a message during user creation"""
|
|
|
|
# Create a user who hasn't had historical messages added
|
2016-12-08 01:43:15 +01:00
|
|
|
stream_dict = {
|
|
|
|
"Denmark": {"description": "A Scandinavian country", "invite_only": False},
|
|
|
|
"Verona": {"description": "A city in Italy", "invite_only": False}
|
|
|
|
} # type: Dict[Text, Dict[Text, Any]]
|
2017-01-04 05:30:48 +01:00
|
|
|
set_default_streams(get_realm("zulip"), stream_dict)
|
2016-11-11 05:33:30 +01:00
|
|
|
with patch("zerver.lib.actions.add_new_user_history"):
|
2017-01-04 09:00:26 +01:00
|
|
|
self.register("test@zulip.com", "test")
|
2016-11-11 05:33:30 +01:00
|
|
|
user_profile = get_user_profile_by_email("test@zulip.com")
|
|
|
|
|
|
|
|
subs = Subscription.objects.select_related("recipient").filter(
|
|
|
|
user_profile=user_profile, recipient__type=Recipient.STREAM)
|
|
|
|
streams = Stream.objects.filter(id__in=[sub.recipient.type_id for sub in subs])
|
|
|
|
self.send_message("hamlet@zulip.com", streams[0].name, Recipient.STREAM, "test")
|
|
|
|
add_new_user_history(user_profile, streams)
|
|
|
|
|
2016-09-13 22:49:03 +02:00
|
|
|
class PasswordResetTest(ZulipTestCase):
|
|
|
|
"""
|
|
|
|
Log in, reset password, log out, log in with new password.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def test_password_reset(self):
|
|
|
|
# type: () -> None
|
|
|
|
email = 'hamlet@zulip.com'
|
|
|
|
old_password = initial_password(email)
|
|
|
|
|
|
|
|
self.login(email)
|
|
|
|
|
2016-12-01 08:54:21 +01:00
|
|
|
# test password reset template
|
|
|
|
result = self.client_get('/accounts/password/reset/')
|
|
|
|
self.assert_in_response('Reset your password.', result)
|
|
|
|
|
2016-09-13 22:49:03 +02:00
|
|
|
# start the password reset process by supplying an email address
|
|
|
|
result = self.client_post('/accounts/password/reset/', {'email': email})
|
|
|
|
|
|
|
|
# check the redirect link telling you to check mail for password reset link
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-09-13 22:49:03 +02:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/password/reset/done/"))
|
2016-09-13 22:49:03 +02:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
|
|
|
|
self.assert_in_response("Check your email to finish the process.", result)
|
|
|
|
|
2016-09-23 04:23:48 +02:00
|
|
|
# Visit the password reset link.
|
|
|
|
password_reset_url = self.get_confirmation_url_from_outbox(email, "(\S+)")
|
2016-09-13 22:49:03 +02:00
|
|
|
result = self.client_get(password_reset_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-09-13 22:49:03 +02:00
|
|
|
|
|
|
|
# Reset your password
|
|
|
|
result = self.client_post(password_reset_url,
|
|
|
|
{'new_password1': 'new_password',
|
|
|
|
'new_password2': 'new_password'})
|
|
|
|
|
|
|
|
# password reset succeeded
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-09-13 22:49:03 +02:00
|
|
|
self.assertTrue(result["Location"].endswith("/password/done/"))
|
|
|
|
|
|
|
|
# log back in with new password
|
|
|
|
self.login(email, password='new_password')
|
|
|
|
user_profile = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
|
|
|
|
|
|
|
# make sure old password no longer works
|
|
|
|
self.login(email, password=old_password, fails=True)
|
|
|
|
|
2016-11-14 19:13:59 +01:00
|
|
|
def test_redirect_endpoints(self):
|
|
|
|
# type: () -> None
|
|
|
|
'''
|
|
|
|
These tests are mostly designed to give us 100% URL coverage
|
|
|
|
in our URL coverage reports. Our mechanism for finding URL
|
|
|
|
coverage doesn't handle redirects, so we just have a few quick
|
|
|
|
tests here.
|
|
|
|
'''
|
|
|
|
result = self.client_get('/accounts/password/reset/done/')
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["Check your email"], result)
|
2016-11-14 19:13:59 +01:00
|
|
|
|
|
|
|
result = self.client_get('/accounts/password/done/')
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["We've reset your password!"], result)
|
2016-11-14 19:13:59 +01:00
|
|
|
|
|
|
|
result = self.client_get('/accounts/send_confirm/alice@example.com')
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["Still no email?"], result)
|
2016-11-14 19:13:59 +01:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class LoginTest(ZulipTestCase):
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Logging in, registration, and logging out.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def test_login(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
user_profile = get_user_profile_by_email('hamlet@zulip.com')
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_login_bad_password(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2016-06-27 20:45:41 +02:00
|
|
|
self.login("hamlet@zulip.com", password="wrongpassword", fails=True)
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertIsNone(get_session_dict_user(self.client.session))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_login_nonexist_user(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2016-06-27 20:36:04 +02:00
|
|
|
result = self.login_with_return("xxx@zulip.com", "xxx")
|
2016-07-12 15:41:45 +02:00
|
|
|
self.assert_in_response("Please enter a correct email and password", result)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_register(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm("zulip")
|
2016-12-08 01:43:15 +01:00
|
|
|
stream_dict = {"stream_"+str(i): {"description": "stream_%s_description" % i, "invite_only": False}
|
2016-12-11 14:30:45 +01:00
|
|
|
for i in range(40)} # type: Dict[Text, Dict[Text, Any]]
|
2016-12-08 01:43:15 +01:00
|
|
|
for stream_name in stream_dict.keys():
|
2016-10-21 23:08:52 +02:00
|
|
|
self.make_stream(stream_name, realm=realm)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2016-12-08 01:43:15 +01:00
|
|
|
set_default_streams(realm, stream_dict)
|
2014-01-31 21:08:40 +01:00
|
|
|
with queries_captured() as queries:
|
2017-01-04 09:00:26 +01:00
|
|
|
self.register("test@zulip.com", "test")
|
2014-01-31 21:08:40 +01:00
|
|
|
# Ensure the number of queries we make is not O(streams)
|
2016-09-29 07:19:13 +02:00
|
|
|
self.assert_max_length(queries, 69)
|
2014-01-31 21:08:40 +01:00
|
|
|
user_profile = get_user_profile_by_email('test@zulip.com')
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
2016-11-08 16:45:48 +01:00
|
|
|
self.assertFalse(user_profile.enable_stream_desktop_notifications)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_register_deactivated(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
If you try to register for a deactivated realm, you get a clear error
|
|
|
|
page.
|
|
|
|
"""
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm("zulip")
|
2014-01-31 21:08:40 +01:00
|
|
|
realm.deactivated = True
|
|
|
|
realm.save(update_fields=["deactivated"])
|
|
|
|
|
2017-01-04 09:00:26 +01:00
|
|
|
result = self.register("test@zulip.com", "test")
|
2016-07-12 23:15:27 +02:00
|
|
|
self.assert_in_response("has been deactivated", result)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
with self.assertRaises(UserProfile.DoesNotExist):
|
|
|
|
get_user_profile_by_email('test@zulip.com')
|
|
|
|
|
|
|
|
def test_login_deactivated(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
If you try to log in to a deactivated realm, you get a clear error page.
|
|
|
|
"""
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm("zulip")
|
2014-01-31 21:08:40 +01:00
|
|
|
realm.deactivated = True
|
|
|
|
realm.save(update_fields=["deactivated"])
|
|
|
|
|
2016-06-27 20:36:04 +02:00
|
|
|
result = self.login_with_return("hamlet@zulip.com")
|
2016-07-12 23:15:27 +02:00
|
|
|
self.assert_in_response("has been deactivated", result)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_logout(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
self.login("hamlet@zulip.com")
|
2016-07-28 00:30:22 +02:00
|
|
|
self.client_post('/accounts/logout/')
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertIsNone(get_session_dict_user(self.client.session))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_non_ascii_login(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
You can log in even if your password contain non-ASCII characters.
|
|
|
|
"""
|
|
|
|
email = "test@zulip.com"
|
2015-11-01 17:15:05 +01:00
|
|
|
password = u"hümbüǵ"
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# Registering succeeds.
|
2017-01-04 09:00:26 +01:00
|
|
|
self.register("test@zulip.com", password)
|
2014-01-31 21:08:40 +01:00
|
|
|
user_profile = get_user_profile_by_email(email)
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
2016-07-28 00:30:22 +02:00
|
|
|
self.client_post('/accounts/logout/')
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertIsNone(get_session_dict_user(self.client.session))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# Logging in succeeds.
|
2016-07-28 00:30:22 +02:00
|
|
|
self.client_post('/accounts/logout/')
|
2014-01-31 21:08:40 +01:00
|
|
|
self.login(email, password)
|
2015-08-19 20:53:55 +02:00
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2017-01-28 20:28:17 +01:00
|
|
|
def test_login_page_redirects_logged_in_user(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""You will be redirected to the app's main page if you land on the
|
|
|
|
login page when already logged in.
|
|
|
|
"""
|
|
|
|
self.login("cordelia@zulip.com")
|
|
|
|
response = self.client_get("/login/")
|
|
|
|
self.assertEqual(response["Location"], "/")
|
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class InviteUserTest(ZulipTestCase):
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2017-02-12 21:21:31 +01:00
|
|
|
def invite(self, users, streams, body=''):
|
|
|
|
# type: (str, List[Text], str) -> HttpResponse
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Invites the specified users to Zulip with the specified streams.
|
|
|
|
|
|
|
|
users should be a string containing the users to invite, comma or
|
|
|
|
newline separated.
|
|
|
|
|
|
|
|
streams should be a list of strings.
|
|
|
|
"""
|
|
|
|
|
2016-07-28 00:30:22 +02:00
|
|
|
return self.client_post("/json/invite_users",
|
2016-12-03 00:04:17 +01:00
|
|
|
{"invitee_emails": users,
|
2017-02-12 21:21:31 +01:00
|
|
|
"stream": streams,
|
|
|
|
"custom_body": body})
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2017-02-12 21:21:31 +01:00
|
|
|
def check_sent_emails(self, correct_recipients, custom_body=None):
|
|
|
|
# type: (List[str], Optional[str]) -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
from django.core.mail import outbox
|
|
|
|
self.assertEqual(len(outbox), len(correct_recipients))
|
|
|
|
email_recipients = [email.recipients()[0] for email in outbox]
|
2016-07-10 20:43:58 +02:00
|
|
|
self.assertEqual(sorted(email_recipients), sorted(correct_recipients))
|
2017-02-12 21:21:31 +01:00
|
|
|
if len(outbox) == 0:
|
|
|
|
return
|
|
|
|
|
|
|
|
if custom_body is None:
|
|
|
|
self.assertNotIn("Message from", outbox[0].body)
|
|
|
|
else:
|
|
|
|
self.assertIn("Message from ", outbox[0].body)
|
|
|
|
self.assertIn(custom_body, outbox[0].body)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_bulk_invite_users(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
|
|
|
"""The bulk_invite_users code path is for the first user in a realm."""
|
2014-01-31 21:08:40 +01:00
|
|
|
self.login('hamlet@zulip.com')
|
|
|
|
invitees = ['alice@zulip.com', 'bob@zulip.com']
|
|
|
|
params = {
|
2017-02-12 21:21:31 +01:00
|
|
|
'invitee_emails': ujson.dumps(invitees),
|
2014-01-31 21:08:40 +01:00
|
|
|
}
|
2016-07-28 00:30:22 +02:00
|
|
|
result = self.client_post('/json/bulk_invite_users', params)
|
2014-01-31 21:08:40 +01:00
|
|
|
self.assert_json_success(result)
|
|
|
|
self.check_sent_emails(invitees)
|
|
|
|
|
2017-02-27 00:29:33 +01:00
|
|
|
def test_bulk_invite_users_invalid_emails(self):
|
|
|
|
# type: () -> None
|
|
|
|
self.login('hamlet@zulip.com')
|
|
|
|
invitees = ['alice@zulip.com', 'bobnoatzulip.com']
|
|
|
|
params = {
|
|
|
|
'invitee_emails': ujson.dumps(invitees),
|
|
|
|
}
|
|
|
|
self.assert_json_error(
|
|
|
|
self.client_post('/json/bulk_invite_users', params),
|
|
|
|
'Some emails did not validate, so we didn\'t send any invitations.')
|
|
|
|
self.check_sent_emails([])
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
def test_successful_invite_user(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
A call to /json/invite_users with valid parameters causes an invitation
|
|
|
|
email to be sent.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
self.assert_json_success(self.invite(invitee, ["Denmark"]))
|
|
|
|
self.assertTrue(find_key_by_email(invitee))
|
|
|
|
self.check_sent_emails([invitee])
|
|
|
|
|
2017-02-12 21:21:31 +01:00
|
|
|
def test_successful_invite_user_with_custom_body(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
A call to /json/invite_users with valid parameters causes an invitation
|
|
|
|
email to be sent.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
body = "Custom Text."
|
|
|
|
self.assert_json_success(self.invite(invitee, ["Denmark"], body))
|
|
|
|
self.assertTrue(find_pattern_in_email(invitee, body))
|
|
|
|
self.check_sent_emails([invitee], custom_body=body)
|
|
|
|
|
2016-07-29 18:16:54 +02:00
|
|
|
def test_successful_invite_user_with_name(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
A call to /json/invite_users with valid parameters causes an invitation
|
|
|
|
email to be sent.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
email = "alice-test@zulip.com"
|
|
|
|
invitee = "Alice Test <{}>".format(email)
|
|
|
|
self.assert_json_success(self.invite(invitee, ["Denmark"]))
|
|
|
|
self.assertTrue(find_key_by_email(email))
|
|
|
|
self.check_sent_emails([email])
|
|
|
|
|
|
|
|
def test_successful_invite_user_with_name_and_normal_one(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
A call to /json/invite_users with valid parameters causes an invitation
|
|
|
|
email to be sent.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
email = "alice-test@zulip.com"
|
|
|
|
email2 = "bob-test@zulip.com"
|
|
|
|
invitee = "Alice Test <{}>, {}".format(email, email2)
|
|
|
|
self.assert_json_success(self.invite(invitee, ["Denmark"]))
|
|
|
|
self.assertTrue(find_key_by_email(email))
|
|
|
|
self.assertTrue(find_key_by_email(email2))
|
|
|
|
self.check_sent_emails([email, email2])
|
|
|
|
|
2017-02-27 00:29:33 +01:00
|
|
|
def test_successful_invite_user_with_notifications_stream(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
A call to /json/invite_users with valid parameters unconditionally
|
|
|
|
subscribes the invitee to the notifications stream if it exists and is
|
|
|
|
public.
|
|
|
|
"""
|
|
|
|
realm = get_realm('zulip')
|
|
|
|
notifications_stream = get_stream('Verona', realm)
|
|
|
|
realm.notifications_stream = notifications_stream
|
|
|
|
realm.save()
|
|
|
|
|
|
|
|
self.login('hamlet@zulip.com')
|
|
|
|
invitee = 'alice-test@zulip.com'
|
|
|
|
self.assert_json_success(self.invite(invitee, ['Denmark']))
|
|
|
|
self.assertTrue(find_key_by_email(invitee))
|
|
|
|
self.check_sent_emails([invitee])
|
|
|
|
|
|
|
|
prereg_user = get_prereg_user_by_email(invitee)
|
|
|
|
streams = list(prereg_user.streams.all())
|
|
|
|
self.assertTrue(notifications_stream in streams)
|
|
|
|
|
2015-10-26 16:49:22 +01:00
|
|
|
def test_invite_user_signup_initial_history(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2015-10-26 16:49:22 +01:00
|
|
|
"""
|
|
|
|
Test that a new user invited to a stream receives some initial
|
|
|
|
history but only from public streams.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
user_profile = get_user_profile_by_email("hamlet@zulip.com")
|
|
|
|
private_stream_name = "Secret"
|
2016-10-21 23:08:52 +02:00
|
|
|
self.make_stream(private_stream_name, invite_only=True)
|
2016-10-20 00:27:20 +02:00
|
|
|
self.subscribe_to_stream(user_profile.email, private_stream_name)
|
2015-10-26 16:49:22 +01:00
|
|
|
public_msg_id = self.send_message("hamlet@zulip.com", "Denmark", Recipient.STREAM,
|
|
|
|
"Public topic", "Public message")
|
|
|
|
secret_msg_id = self.send_message("hamlet@zulip.com", private_stream_name, Recipient.STREAM,
|
|
|
|
"Secret topic", "Secret message")
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
self.assert_json_success(self.invite(invitee, [private_stream_name, "Denmark"]))
|
|
|
|
self.assertTrue(find_key_by_email(invitee))
|
|
|
|
|
2017-01-04 08:53:56 +01:00
|
|
|
self.submit_reg_form_for_user("alice-test@zulip.com", "password")
|
2015-10-26 16:49:22 +01:00
|
|
|
invitee_profile = get_user_profile_by_email(invitee)
|
|
|
|
invitee_msg_ids = [um.message_id for um in
|
|
|
|
UserMessage.objects.filter(user_profile=invitee_profile)]
|
|
|
|
self.assertTrue(public_msg_id in invitee_msg_ids)
|
|
|
|
self.assertFalse(secret_msg_id in invitee_msg_ids)
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
def test_multi_user_invite(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Invites multiple users with a variety of delimiters.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
# Intentionally use a weird string.
|
|
|
|
self.assert_json_success(self.invite(
|
2016-12-02 08:15:16 +01:00
|
|
|
"""bob-test@zulip.com, carol-test@zulip.com,
|
|
|
|
dave-test@zulip.com
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
earl-test@zulip.com""", ["Denmark"]))
|
|
|
|
for user in ("bob", "carol", "dave", "earl"):
|
2015-12-01 17:11:16 +01:00
|
|
|
self.assertTrue(find_key_by_email("%s-test@zulip.com" % (user,)))
|
2014-01-31 21:08:40 +01:00
|
|
|
self.check_sent_emails(["bob-test@zulip.com", "carol-test@zulip.com",
|
|
|
|
"dave-test@zulip.com", "earl-test@zulip.com"])
|
|
|
|
|
|
|
|
def test_missing_or_invalid_params(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Tests inviting with various missing or invalid parameters.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
self.assert_json_error(
|
2017-02-12 21:21:31 +01:00
|
|
|
self.client_post("/json/invite_users", {"invitee_emails": "foo@zulip.com",
|
|
|
|
"custom_body": ''}),
|
2014-01-31 21:08:40 +01:00
|
|
|
"You must specify at least one stream for invitees to join.")
|
|
|
|
|
|
|
|
for address in ("noatsign.com", "outsideyourdomain@example.net"):
|
|
|
|
self.assert_json_error(
|
|
|
|
self.invite(address, ["Denmark"]),
|
|
|
|
"Some emails did not validate, so we didn't send any invitations.")
|
|
|
|
self.check_sent_emails([])
|
|
|
|
|
2017-02-27 00:29:33 +01:00
|
|
|
self.assert_json_error(
|
|
|
|
self.invite("", ["Denmark"]),
|
|
|
|
"You must specify at least one email address.")
|
|
|
|
self.check_sent_emails([])
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
def test_invalid_stream(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Tests inviting to a non-existent stream.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
self.assert_json_error(self.invite("iago-test@zulip.com", ["NotARealStream"]),
|
2016-12-03 00:04:17 +01:00
|
|
|
"Stream does not exist: NotARealStream. No invites were sent.")
|
2014-01-31 21:08:40 +01:00
|
|
|
self.check_sent_emails([])
|
|
|
|
|
|
|
|
def test_invite_existing_user(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
If you invite an address already using Zulip, no invitation is sent.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
self.assert_json_error(
|
2016-07-28 00:30:22 +02:00
|
|
|
self.client_post("/json/invite_users",
|
2014-01-31 21:08:40 +01:00
|
|
|
{"invitee_emails": "hamlet@zulip.com",
|
2017-02-12 21:21:31 +01:00
|
|
|
"stream": ["Denmark"],
|
|
|
|
"custom_body": ''}),
|
2014-01-31 21:08:40 +01:00
|
|
|
"We weren't able to invite anyone.")
|
|
|
|
self.assertRaises(PreregistrationUser.DoesNotExist,
|
|
|
|
lambda: PreregistrationUser.objects.get(
|
2017-01-24 06:02:39 +01:00
|
|
|
email="hamlet@zulip.com"))
|
2014-01-31 21:08:40 +01:00
|
|
|
self.check_sent_emails([])
|
|
|
|
|
|
|
|
def test_invite_some_existing_some_new(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
If you invite a mix of already existing and new users, invitations are
|
|
|
|
only sent to the new users.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
existing = ["hamlet@zulip.com", "othello@zulip.com"]
|
|
|
|
new = ["foo-test@zulip.com", "bar-test@zulip.com"]
|
|
|
|
|
2016-07-28 00:30:22 +02:00
|
|
|
result = self.client_post("/json/invite_users",
|
2014-01-31 21:08:40 +01:00
|
|
|
{"invitee_emails": "\n".join(existing + new),
|
2017-02-12 21:21:31 +01:00
|
|
|
"stream": ["Denmark"],
|
|
|
|
"custom_body": ''})
|
2014-01-31 21:08:40 +01:00
|
|
|
self.assert_json_error(result,
|
|
|
|
"Some of those addresses are already using Zulip, \
|
|
|
|
so we didn't send them an invitation. We did send invitations to everyone else!")
|
|
|
|
|
|
|
|
# We only created accounts for the new users.
|
|
|
|
for email in existing:
|
|
|
|
self.assertRaises(PreregistrationUser.DoesNotExist,
|
|
|
|
lambda: PreregistrationUser.objects.get(
|
2017-01-24 06:02:39 +01:00
|
|
|
email=email))
|
2014-01-31 21:08:40 +01:00
|
|
|
for email in new:
|
|
|
|
self.assertTrue(PreregistrationUser.objects.get(email=email))
|
|
|
|
|
|
|
|
# We only sent emails to the new users.
|
|
|
|
self.check_sent_emails(new)
|
|
|
|
|
2016-10-04 01:15:24 +02:00
|
|
|
prereg_user = get_prereg_user_by_email('foo-test@zulip.com')
|
|
|
|
self.assertEqual(prereg_user.email, 'foo-test@zulip.com')
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
def test_invite_outside_domain_in_closed_realm(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
In a realm with `restricted_to_domain = True`, you can't invite people
|
|
|
|
with a different domain from that of the realm or your e-mail address.
|
|
|
|
"""
|
2017-01-04 05:30:48 +01:00
|
|
|
zulip_realm = get_realm("zulip")
|
2014-01-31 21:08:40 +01:00
|
|
|
zulip_realm.restricted_to_domain = True
|
|
|
|
zulip_realm.save()
|
|
|
|
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
external_address = "foo@example.com"
|
|
|
|
|
|
|
|
self.assert_json_error(
|
|
|
|
self.invite(external_address, ["Denmark"]),
|
|
|
|
"Some emails did not validate, so we didn't send any invitations.")
|
|
|
|
|
|
|
|
def test_invite_outside_domain_in_open_realm(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
In a realm with `restricted_to_domain = False`, you can invite people
|
|
|
|
with a different domain from that of the realm or your e-mail address.
|
|
|
|
"""
|
2017-01-04 05:30:48 +01:00
|
|
|
zulip_realm = get_realm("zulip")
|
2014-01-31 21:08:40 +01:00
|
|
|
zulip_realm.restricted_to_domain = False
|
|
|
|
zulip_realm.save()
|
|
|
|
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
external_address = "foo@example.com"
|
|
|
|
|
|
|
|
self.assert_json_success(self.invite(external_address, ["Denmark"]))
|
|
|
|
self.check_sent_emails([external_address])
|
|
|
|
|
|
|
|
def test_invite_with_non_ascii_streams(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
Inviting someone to streams with non-ASCII characters succeeds.
|
|
|
|
"""
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
|
2015-11-01 17:15:05 +01:00
|
|
|
stream_name = u"hümbüǵ"
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# Make sure we're subscribed before inviting someone.
|
2016-10-20 00:27:20 +02:00
|
|
|
self.subscribe_to_stream("hamlet@zulip.com", stream_name)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
self.assert_json_success(self.invite(invitee, [stream_name]))
|
|
|
|
|
2016-11-24 20:26:55 +01:00
|
|
|
def test_refer_friend(self):
|
|
|
|
# type: () -> None
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
2016-11-28 23:29:01 +01:00
|
|
|
user.invites_granted = 1
|
|
|
|
user.invites_used = 0
|
2016-11-24 20:26:55 +01:00
|
|
|
user.save()
|
|
|
|
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
result = self.client_post('/json/refer_friend', dict(email=invitee))
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
|
|
|
# verify this works
|
|
|
|
Referral.objects.get(user_profile=user, email=invitee)
|
|
|
|
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertEqual(user.invites_used, 1)
|
|
|
|
|
2017-02-27 00:29:33 +01:00
|
|
|
def test_refer_friend_no_email(self):
|
|
|
|
# type: () -> None
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
user.invites_granted = 1
|
|
|
|
user.invites_used = 0
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
self.assert_json_error(
|
|
|
|
self.client_post('/json/refer_friend', dict(email='')),
|
|
|
|
"No email address specified")
|
|
|
|
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertEqual(user.invites_used, 0)
|
|
|
|
|
|
|
|
def test_refer_friend_no_invites(self):
|
|
|
|
# type: () -> None
|
|
|
|
self.login("hamlet@zulip.com")
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
user.invites_granted = 1
|
|
|
|
user.invites_used = 1
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
self.assert_json_error(
|
|
|
|
self.client_post('/json/refer_friend', dict(email=invitee)),
|
|
|
|
"Insufficient invites")
|
|
|
|
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertEqual(user.invites_used, 1)
|
|
|
|
|
2016-12-01 08:54:21 +01:00
|
|
|
def test_invitation_reminder_email(self):
|
|
|
|
# type: () -> None
|
|
|
|
from django.core.mail import outbox
|
|
|
|
current_user_email = "hamlet@zulip.com"
|
|
|
|
self.login(current_user_email)
|
|
|
|
invitee = "alice-test@zulip.com"
|
|
|
|
self.assert_json_success(self.invite(invitee, ["Denmark"]))
|
|
|
|
self.assertTrue(find_key_by_email(invitee))
|
|
|
|
self.check_sent_emails([invitee])
|
|
|
|
|
|
|
|
data = {"email": invitee, "referrer_email": current_user_email}
|
|
|
|
invitee = get_prereg_user_by_email(data["email"])
|
|
|
|
referrer = get_user_profile_by_email(data["referrer_email"])
|
|
|
|
link = Confirmation.objects.get_link_for_object(invitee, host=referrer.realm.host)
|
|
|
|
context = common_context(referrer)
|
|
|
|
context.update({
|
|
|
|
'activate_url': link,
|
|
|
|
'referrer': referrer,
|
|
|
|
'verbose_support_offers': settings.VERBOSE_SUPPORT_OFFERS,
|
|
|
|
'support_email': settings.ZULIP_ADMINISTRATOR
|
|
|
|
})
|
|
|
|
with self.settings(EMAIL_BACKEND='django.core.mail.backends.console.EmailBackend'):
|
|
|
|
send_local_email_template_with_delay(
|
|
|
|
[{'email': data["email"], 'name': ""}],
|
|
|
|
"zerver/emails/invitation/invitation_reminder_email",
|
|
|
|
context,
|
|
|
|
datetime.timedelta(days=0),
|
|
|
|
tags=["invitation-reminders"],
|
|
|
|
sender={'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'})
|
|
|
|
email_jobs_to_deliver = ScheduledJob.objects.filter(
|
|
|
|
type=ScheduledJob.EMAIL,
|
|
|
|
scheduled_timestamp__lte=datetime.datetime.utcnow())
|
|
|
|
self.assertEqual(len(email_jobs_to_deliver), 1)
|
|
|
|
email_count = len(outbox)
|
|
|
|
for job in email_jobs_to_deliver:
|
|
|
|
self.assertTrue(send_email_job(job))
|
|
|
|
self.assertEqual(len(outbox), email_count + 1)
|
|
|
|
|
2016-07-29 18:16:54 +02:00
|
|
|
class InviteeEmailsParserTests(TestCase):
|
|
|
|
def setUp(self):
|
2016-09-10 20:34:33 +02:00
|
|
|
# type: () -> None
|
2016-07-29 18:16:54 +02:00
|
|
|
self.email1 = "email1@zulip.com"
|
|
|
|
self.email2 = "email2@zulip.com"
|
|
|
|
self.email3 = "email3@zulip.com"
|
|
|
|
|
|
|
|
def test_if_emails_separated_by_commas_are_parsed_and_striped_correctly(self):
|
2016-09-10 20:34:33 +02:00
|
|
|
# type: () -> None
|
2016-07-29 18:16:54 +02:00
|
|
|
emails_raw = "{} ,{}, {}".format(self.email1, self.email2, self.email3)
|
|
|
|
expected_set = {self.email1, self.email2, self.email3}
|
|
|
|
self.assertEqual(get_invitee_emails_set(emails_raw), expected_set)
|
|
|
|
|
|
|
|
def test_if_emails_separated_by_newlines_are_parsed_and_striped_correctly(self):
|
2016-09-10 20:34:33 +02:00
|
|
|
# type: () -> None
|
2016-07-29 18:16:54 +02:00
|
|
|
emails_raw = "{}\n {}\n {} ".format(self.email1, self.email2, self.email3)
|
|
|
|
expected_set = {self.email1, self.email2, self.email3}
|
|
|
|
self.assertEqual(get_invitee_emails_set(emails_raw), expected_set)
|
|
|
|
|
|
|
|
def test_if_emails_from_email_client_separated_by_newlines_are_parsed_correctly(self):
|
2016-09-10 20:34:33 +02:00
|
|
|
# type: () -> None
|
2016-07-29 18:16:54 +02:00
|
|
|
emails_raw = "Email One <{}>\nEmailTwo<{}>\nEmail Three<{}>".format(self.email1, self.email2, self.email3)
|
|
|
|
expected_set = {self.email1, self.email2, self.email3}
|
|
|
|
self.assertEqual(get_invitee_emails_set(emails_raw), expected_set)
|
|
|
|
|
|
|
|
def test_if_emails_in_mixed_style_are_parsed_correctly(self):
|
2016-09-10 20:34:33 +02:00
|
|
|
# type: () -> None
|
2016-07-29 18:16:54 +02:00
|
|
|
emails_raw = "Email One <{}>,EmailTwo<{}>\n{}".format(self.email1, self.email2, self.email3)
|
|
|
|
expected_set = {self.email1, self.email2, self.email3}
|
|
|
|
self.assertEqual(get_invitee_emails_set(emails_raw), expected_set)
|
|
|
|
|
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class EmailUnsubscribeTests(ZulipTestCase):
|
2016-12-01 08:54:21 +01:00
|
|
|
def test_error_unsubscribe(self):
|
|
|
|
# type: () -> None
|
2017-02-26 21:48:38 +01:00
|
|
|
|
|
|
|
# An invalid insubscribe token "test123" produces an error.
|
2016-12-01 08:54:21 +01:00
|
|
|
result = self.client_get('/accounts/unsubscribe/missed_messages/test123')
|
|
|
|
self.assert_in_response('Unknown email unsubscribe request', result)
|
|
|
|
|
2017-02-26 21:48:38 +01:00
|
|
|
# An unknown message type "fake" produces an error.
|
|
|
|
user_profile = get_user_profile_by_email("hamlet@zulip.com")
|
|
|
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "fake")
|
|
|
|
result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path)
|
|
|
|
self.assert_in_response('Unknown email unsubscribe request', result)
|
|
|
|
|
2014-01-31 21:08:40 +01:00
|
|
|
def test_missedmessage_unsubscribe(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
We provide one-click unsubscribe links in missed message
|
|
|
|
e-mails that you can click even when logged out to update your
|
|
|
|
email notification settings.
|
|
|
|
"""
|
|
|
|
user_profile = get_user_profile_by_email("hamlet@zulip.com")
|
|
|
|
user_profile.enable_offline_email_notifications = True
|
|
|
|
user_profile.save()
|
|
|
|
|
|
|
|
unsubscribe_link = one_click_unsubscribe_link(user_profile,
|
|
|
|
"missed_messages")
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
# Circumvent user_profile caching.
|
|
|
|
user_profile = UserProfile.objects.get(email="hamlet@zulip.com")
|
|
|
|
self.assertFalse(user_profile.enable_offline_email_notifications)
|
|
|
|
|
|
|
|
def test_welcome_unsubscribe(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
We provide one-click unsubscribe links in welcome e-mails that you can
|
|
|
|
click even when logged out to stop receiving them.
|
|
|
|
"""
|
|
|
|
email = "hamlet@zulip.com"
|
|
|
|
user_profile = get_user_profile_by_email("hamlet@zulip.com")
|
|
|
|
|
|
|
|
# Simulate a new user signing up, which enqueues 2 welcome e-mails.
|
|
|
|
enqueue_welcome_emails(email, "King Hamlet")
|
|
|
|
self.assertEqual(2, len(ScheduledJob.objects.filter(
|
2017-01-24 07:06:13 +01:00
|
|
|
type=ScheduledJob.EMAIL, filter_string__iexact=email)))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# Simulate unsubscribing from the welcome e-mails.
|
|
|
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# The welcome email jobs are no longer scheduled.
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertEqual(0, len(ScheduledJob.objects.filter(
|
2017-01-24 07:06:13 +01:00
|
|
|
type=ScheduledJob.EMAIL, filter_string__iexact=email)))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
def test_digest_unsubscribe(self):
|
2016-06-04 20:14:05 +02:00
|
|
|
# type: () -> None
|
2014-01-31 21:08:40 +01:00
|
|
|
"""
|
|
|
|
We provide one-click unsubscribe links in digest e-mails that you can
|
|
|
|
click even when logged out to stop receiving them.
|
|
|
|
|
|
|
|
Unsubscribing from these emails also dequeues any digest email jobs that
|
|
|
|
have been queued.
|
|
|
|
"""
|
|
|
|
email = "hamlet@zulip.com"
|
|
|
|
user_profile = get_user_profile_by_email("hamlet@zulip.com")
|
|
|
|
self.assertTrue(user_profile.enable_digest_emails)
|
|
|
|
|
|
|
|
# Enqueue a fake digest email.
|
2017-01-05 02:10:12 +01:00
|
|
|
send_digest_email(user_profile, "", "", "")
|
2014-01-31 21:08:40 +01:00
|
|
|
self.assertEqual(1, len(ScheduledJob.objects.filter(
|
2017-01-24 07:06:13 +01:00
|
|
|
type=ScheduledJob.EMAIL, filter_string__iexact=email)))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# Simulate unsubscribing from digest e-mails.
|
|
|
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "digest")
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path)
|
2014-01-31 21:08:40 +01:00
|
|
|
|
|
|
|
# The setting is toggled off, and scheduled jobs have been removed.
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
# Circumvent user_profile caching.
|
|
|
|
user_profile = UserProfile.objects.get(email="hamlet@zulip.com")
|
|
|
|
self.assertFalse(user_profile.enable_digest_emails)
|
|
|
|
self.assertEqual(0, len(ScheduledJob.objects.filter(
|
2017-01-24 07:06:13 +01:00
|
|
|
type=ScheduledJob.EMAIL, filter_string__iexact=email)))
|
2014-01-31 21:08:40 +01:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class RealmCreationTest(ZulipTestCase):
|
2016-06-03 01:02:58 +02:00
|
|
|
|
|
|
|
def test_create_realm(self):
|
|
|
|
# type: () -> None
|
|
|
|
password = "test"
|
2016-10-31 23:28:20 +01:00
|
|
|
string_id = "zuliptest"
|
2016-06-03 01:02:58 +02:00
|
|
|
email = "user1@test.com"
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('test')
|
2016-06-03 01:02:58 +02:00
|
|
|
|
|
|
|
# Make sure the realm does not exist
|
2016-11-07 21:49:36 +01:00
|
|
|
self.assertIsNone(realm)
|
2016-06-03 01:02:58 +02:00
|
|
|
|
|
|
|
with self.settings(OPEN_REALM_CREATION=True):
|
|
|
|
# Create new realm with the email
|
2016-07-28 00:30:22 +02:00
|
|
|
result = self.client_post('/create_realm/', {'email': email})
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-06-03 01:02:58 +02:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get(result["Location"])
|
2016-07-12 15:41:45 +02:00
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
2016-06-03 01:02:58 +02:00
|
|
|
|
|
|
|
# Visit the confirmation link.
|
2016-09-23 04:23:48 +02:00
|
|
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
2016-07-28 00:38:45 +02:00
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-06-03 01:02:58 +02:00
|
|
|
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email, password, realm_subdomain=string_id)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-06-03 01:02:58 +02:00
|
|
|
|
|
|
|
# Make sure the realm is created
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm(string_id)
|
2016-06-03 01:02:58 +02:00
|
|
|
self.assertIsNotNone(realm)
|
2016-10-28 07:21:53 +02:00
|
|
|
self.assertEqual(realm.string_id, string_id)
|
2016-06-03 01:02:58 +02:00
|
|
|
self.assertEqual(get_user_profile_by_email(email).realm, realm)
|
|
|
|
|
2016-09-16 19:05:14 +02:00
|
|
|
# Check defaults
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(realm.org_type, Realm.COMMUNITY)
|
|
|
|
self.assertEqual(realm.restricted_to_domain, False)
|
|
|
|
self.assertEqual(realm.invite_required, True)
|
2016-09-16 19:05:14 +02:00
|
|
|
|
2016-10-06 01:23:27 +02:00
|
|
|
self.assertTrue(result["Location"].endswith("/"))
|
2016-08-04 17:32:41 +02:00
|
|
|
|
2016-07-19 14:35:08 +02:00
|
|
|
def test_create_realm_with_subdomain(self):
|
|
|
|
# type: () -> None
|
|
|
|
password = "test"
|
2016-10-31 23:28:20 +01:00
|
|
|
string_id = "zuliptest"
|
2016-07-19 14:35:08 +02:00
|
|
|
email = "user1@test.com"
|
|
|
|
realm_name = "Test"
|
|
|
|
|
|
|
|
# Make sure the realm does not exist
|
2017-01-04 05:30:48 +01:00
|
|
|
self.assertIsNone(get_realm('test'))
|
2016-11-04 01:33:46 +01:00
|
|
|
|
2016-07-19 14:35:08 +02:00
|
|
|
with self.settings(REALMS_HAVE_SUBDOMAINS=True), self.settings(OPEN_REALM_CREATION=True):
|
|
|
|
# Create new realm with the email
|
|
|
|
result = self.client_post('/create_realm/', {'email': email})
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-07-19 14:35:08 +02:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-07-19 14:35:08 +02:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
|
2016-11-04 01:33:46 +01:00
|
|
|
# Visit the confirmation link.
|
|
|
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
2016-07-19 14:35:08 +02:00
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-07-19 14:35:08 +02:00
|
|
|
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email, password,
|
2016-11-04 01:33:46 +01:00
|
|
|
realm_subdomain = string_id,
|
2016-07-19 14:35:08 +02:00
|
|
|
realm_name=realm_name,
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
2016-11-04 01:33:46 +01:00
|
|
|
HTTP_HOST=string_id + ".testserver")
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-07-19 14:35:08 +02:00
|
|
|
|
|
|
|
# Make sure the realm is created
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm(string_id)
|
2016-07-19 14:35:08 +02:00
|
|
|
self.assertIsNotNone(realm)
|
2016-11-04 01:33:46 +01:00
|
|
|
self.assertEqual(realm.string_id, string_id)
|
2016-07-19 14:35:08 +02:00
|
|
|
self.assertEqual(get_user_profile_by_email(email).realm, realm)
|
2016-10-13 20:09:32 +02:00
|
|
|
|
2016-11-04 01:33:46 +01:00
|
|
|
self.assertEqual(realm.name, realm_name)
|
|
|
|
self.assertEqual(realm.subdomain, string_id)
|
|
|
|
|
2016-11-05 03:26:30 +01:00
|
|
|
def test_mailinator_signup(self):
|
|
|
|
# type: () -> None
|
|
|
|
with self.settings(OPEN_REALM_CREATION=True):
|
|
|
|
result = self.client_post('/create_realm/', {'email': "hi@mailinator.com"})
|
|
|
|
self.assert_in_response('Please use your real email address.', result)
|
|
|
|
|
2016-10-31 23:28:20 +01:00
|
|
|
def test_subdomain_restrictions(self):
|
|
|
|
# type: () -> None
|
|
|
|
password = "test"
|
|
|
|
email = "user1@test.com"
|
|
|
|
realm_name = "Test"
|
|
|
|
|
|
|
|
with self.settings(REALMS_HAVE_SUBDOMAINS=False), self.settings(OPEN_REALM_CREATION=True):
|
|
|
|
result = self.client_post('/create_realm/', {'email': email})
|
|
|
|
self.client_get(result["Location"])
|
|
|
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
|
|
|
self.client_get(confirmation_url)
|
|
|
|
|
|
|
|
errors = {'id': "at least 3 characters",
|
|
|
|
'-id': "cannot start or end with a",
|
|
|
|
'string-ID': "lowercase letters",
|
|
|
|
'string_id': "lowercase letters",
|
|
|
|
'stream': "unavailable",
|
|
|
|
'streams': "unavailable",
|
|
|
|
'about': "unavailable",
|
|
|
|
'abouts': "unavailable",
|
|
|
|
'mit': "unavailable"}
|
|
|
|
for string_id, error_msg in errors.items():
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email, password,
|
2016-10-31 23:28:20 +01:00
|
|
|
realm_subdomain = string_id,
|
|
|
|
realm_name = realm_name)
|
|
|
|
self.assert_in_response(error_msg, result)
|
|
|
|
|
|
|
|
# test valid subdomain
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email, password,
|
2016-10-31 23:28:20 +01:00
|
|
|
realm_subdomain = 'a-0',
|
|
|
|
realm_name = realm_name)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-10-31 23:28:20 +01:00
|
|
|
|
2016-11-04 01:23:43 +01:00
|
|
|
class UserSignUpTest(ZulipTestCase):
|
|
|
|
|
|
|
|
def test_user_default_language(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Check if the default language of new user is the default language
|
|
|
|
of the realm.
|
|
|
|
"""
|
|
|
|
email = "newguy@zulip.com"
|
|
|
|
password = "newpassword"
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('zulip')
|
2016-11-04 01:23:43 +01:00
|
|
|
do_set_realm_default_language(realm, "de")
|
|
|
|
|
|
|
|
result = self.client_post('/accounts/home/', {'email': email})
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-04 01:23:43 +01:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-11-04 01:23:43 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
|
|
|
|
# Visit the confirmation link.
|
|
|
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-11-04 01:23:43 +01:00
|
|
|
|
|
|
|
# Pick a password and agree to the ToS.
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email, password)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-04 01:23:43 +01:00
|
|
|
|
|
|
|
user_profile = get_user_profile_by_email(email)
|
|
|
|
self.assertEqual(user_profile.default_language, realm.default_language)
|
|
|
|
from django.core.mail import outbox
|
|
|
|
outbox.pop()
|
|
|
|
|
2017-02-08 05:04:14 +01:00
|
|
|
def test_signup_invalid_name(self):
|
|
|
|
# type: () -> None
|
|
|
|
"""
|
|
|
|
Check if the default language of new user is the default language
|
|
|
|
of the realm.
|
|
|
|
"""
|
|
|
|
email = "newguy@zulip.com"
|
|
|
|
password = "newpassword"
|
|
|
|
|
|
|
|
result = self.client_post('/accounts/home/', {'email': email})
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
self.assertTrue(result["Location"].endswith(
|
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
|
|
|
|
# Visit the confirmation link.
|
|
|
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
|
|
|
result = self.client_get(confirmation_url)
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
|
|
|
# Pick a password and agree to the ToS.
|
|
|
|
result = self.submit_reg_form_for_user(email, password, full_name="<invalid>")
|
|
|
|
self.assert_in_success_response("Invalid characters in name!", result)
|
|
|
|
|
2016-11-03 20:33:46 +01:00
|
|
|
def test_unique_completely_open_domain(self):
|
2016-10-31 12:18:13 +01:00
|
|
|
# type: () -> None
|
|
|
|
password = "test"
|
|
|
|
email = "user1@acme.com"
|
|
|
|
subdomain = "zulip"
|
|
|
|
realm_name = "Zulip"
|
|
|
|
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('zulip')
|
2016-10-31 12:18:13 +01:00
|
|
|
realm.restricted_to_domain = False
|
|
|
|
realm.invite_required = False
|
|
|
|
realm.save()
|
|
|
|
|
2017-01-27 00:06:55 +01:00
|
|
|
for string_id in ('simple', 'mit'):
|
|
|
|
realm = get_realm(string_id)
|
|
|
|
do_deactivate_realm(realm)
|
|
|
|
realm.save()
|
2016-11-03 20:33:46 +01:00
|
|
|
|
|
|
|
result = self.client_post('/register/', {'email': email})
|
2016-10-31 12:18:13 +01:00
|
|
|
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-10-31 12:18:13 +01:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-10-31 12:18:13 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
# Visit the confirmation link.
|
|
|
|
from django.core.mail import outbox
|
|
|
|
for message in reversed(outbox):
|
|
|
|
if email in message.to:
|
|
|
|
confirmation_link_pattern = re.compile(settings.EXTERNAL_HOST + "(\S+)>")
|
|
|
|
confirmation_url = confirmation_link_pattern.search(
|
|
|
|
message.body).groups()[0]
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise ValueError("Couldn't find a confirmation email.")
|
|
|
|
|
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-10-31 12:18:13 +01:00
|
|
|
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-10-31 12:18:13 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["You're almost there."], result)
|
2016-10-31 12:18:13 +01:00
|
|
|
|
2016-11-01 12:14:31 +01:00
|
|
|
def test_completely_open_domain_success(self):
|
|
|
|
# type: () -> None
|
|
|
|
password = "test"
|
|
|
|
email = "user1@acme.com"
|
|
|
|
subdomain = "zulip"
|
|
|
|
realm_name = "Zulip"
|
|
|
|
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('zulip')
|
2016-11-01 12:14:31 +01:00
|
|
|
realm.restricted_to_domain = False
|
|
|
|
realm.invite_required = False
|
|
|
|
realm.save()
|
|
|
|
|
2016-12-24 07:32:10 +01:00
|
|
|
result = self.client_post('/register/zulip/', {'email': email})
|
2016-11-01 12:14:31 +01:00
|
|
|
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-01 12:14:31 +01:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-11-01 12:14:31 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
# Visit the confirmation link.
|
|
|
|
from django.core.mail import outbox
|
|
|
|
for message in reversed(outbox):
|
|
|
|
if email in message.to:
|
|
|
|
confirmation_link_pattern = re.compile(settings.EXTERNAL_HOST + "(\S+)>")
|
|
|
|
confirmation_url = confirmation_link_pattern.search(
|
|
|
|
message.body).groups()[0]
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise ValueError("Couldn't find a confirmation email.")
|
|
|
|
|
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2016-11-01 12:14:31 +01:00
|
|
|
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-11-01 12:14:31 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["You're almost there."], result)
|
2016-11-01 12:14:31 +01:00
|
|
|
|
2016-11-09 00:47:27 +01:00
|
|
|
def test_failed_signup_due_to_restricted_domain(self):
|
|
|
|
# type: () -> None
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('zulip')
|
2017-01-11 23:06:33 +01:00
|
|
|
realm.invite_required = False
|
|
|
|
realm.save()
|
2016-11-09 00:47:27 +01:00
|
|
|
with self.settings(REALMS_HAVE_SUBDOMAINS = True):
|
|
|
|
request = HostRequestMock(host = realm.host)
|
|
|
|
request.session = {} # type: ignore
|
2016-12-24 04:35:58 +01:00
|
|
|
form = HomepageForm({'email': 'user@acme.com'}, realm=realm)
|
2016-11-09 00:47:27 +01:00
|
|
|
self.assertIn("trying to join, zulip, only allows users with e-mail", form.errors['email'][0])
|
|
|
|
|
|
|
|
def test_failed_signup_due_to_invite_required(self):
|
|
|
|
# type: () -> None
|
2017-01-04 05:30:48 +01:00
|
|
|
realm = get_realm('zulip')
|
2016-11-09 00:47:27 +01:00
|
|
|
realm.invite_required = True
|
|
|
|
realm.save()
|
|
|
|
request = HostRequestMock(host = realm.host)
|
|
|
|
request.session = {} # type: ignore
|
2016-12-24 04:35:58 +01:00
|
|
|
form = HomepageForm({'email': 'user@zulip.com'}, realm=realm)
|
2016-11-09 00:47:27 +01:00
|
|
|
self.assertIn("Please request an invite from", form.errors['email'][0])
|
|
|
|
|
|
|
|
def test_failed_signup_due_to_nonexistent_realm(self):
|
|
|
|
# type: () -> None
|
|
|
|
with self.settings(REALMS_HAVE_SUBDOMAINS = True):
|
|
|
|
request = HostRequestMock(host = 'acme.' + settings.EXTERNAL_HOST)
|
|
|
|
request.session = {} # type: ignore
|
2016-12-24 04:35:58 +01:00
|
|
|
form = HomepageForm({'email': 'user@acme.com'}, realm=None)
|
2016-11-09 00:47:27 +01:00
|
|
|
self.assertIn("organization you are trying to join does not exist", form.errors['email'][0])
|
|
|
|
|
2016-11-02 11:10:21 +01:00
|
|
|
def test_registration_through_ldap(self):
|
|
|
|
# type: () -> None
|
|
|
|
password = "testing"
|
|
|
|
email = "newuser@zulip.com"
|
|
|
|
subdomain = "zulip"
|
|
|
|
realm_name = "Zulip"
|
|
|
|
ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'}
|
|
|
|
|
|
|
|
ldap_patcher = patch('django_auth_ldap.config.ldap.initialize')
|
|
|
|
mock_initialize = ldap_patcher.start()
|
|
|
|
mock_ldap = MockLDAP()
|
|
|
|
mock_initialize.return_value = mock_ldap
|
|
|
|
|
|
|
|
mock_ldap.directory = {
|
|
|
|
'uid=newuser,ou=users,dc=zulip,dc=com': {
|
|
|
|
'userPassword': 'testing',
|
|
|
|
'fn': ['New User Name']
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 21:46:03 +01:00
|
|
|
with patch('zerver.views.registration.get_subdomain', return_value=subdomain):
|
2016-11-02 11:10:21 +01:00
|
|
|
result = self.client_post('/register/', {'email': email})
|
|
|
|
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-02 11:10:21 +01:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-11-02 11:10:21 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
# Visit the confirmation link.
|
|
|
|
from django.core.mail import outbox
|
|
|
|
for message in reversed(outbox):
|
|
|
|
if email in message.to:
|
|
|
|
confirmation_link_pattern = re.compile(settings.EXTERNAL_HOST + "(\S+)>")
|
|
|
|
confirmation_url = confirmation_link_pattern.search(
|
|
|
|
message.body).groups()[0]
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise ValueError("Couldn't find a confirmation email.")
|
|
|
|
|
|
|
|
with self.settings(
|
|
|
|
POPULATE_PROFILE_VIA_LDAP=True,
|
|
|
|
LDAP_APPEND_DOMAIN='zulip.com',
|
|
|
|
AUTH_LDAP_BIND_PASSWORD='',
|
|
|
|
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
|
|
|
|
AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',),
|
|
|
|
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
|
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-11-02 11:10:21 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
from_confirmation='1',
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
|
|
|
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["You're almost there.",
|
|
|
|
"New User Name",
|
|
|
|
"newuser@zulip.com"],
|
|
|
|
result)
|
2016-11-02 11:10:21 +01:00
|
|
|
|
|
|
|
# Test the TypeError exception handler
|
|
|
|
mock_ldap.directory = {
|
|
|
|
'uid=newuser,ou=users,dc=zulip,dc=com': {
|
|
|
|
'userPassword': 'testing',
|
|
|
|
'fn': None # This will raise TypeError
|
|
|
|
}
|
|
|
|
}
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-11-02 11:10:21 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
from_confirmation='1',
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
2016-11-19 21:54:00 +01:00
|
|
|
self.assert_in_success_response(["You're almost there.",
|
|
|
|
"newuser@zulip.com"],
|
|
|
|
result)
|
2016-11-02 11:10:21 +01:00
|
|
|
|
|
|
|
mock_ldap.reset()
|
|
|
|
mock_initialize.stop()
|
|
|
|
|
2016-11-03 21:24:54 +01:00
|
|
|
@patch('DNS.dnslookup', return_value=[['sipbtest:*:20922:101:Fred Sipb,,,:/mit/sipbtest:/bin/athena/tcsh']])
|
|
|
|
def test_registration_of_mirror_dummy_user(self, ignored):
|
|
|
|
# type: (Any) -> None
|
2016-11-02 17:31:11 +01:00
|
|
|
password = "test"
|
|
|
|
email = "sipbtest@mit.edu"
|
2016-10-31 23:28:20 +01:00
|
|
|
subdomain = "sipb"
|
2016-11-02 17:31:11 +01:00
|
|
|
realm_name = "MIT"
|
|
|
|
|
|
|
|
user_profile = get_user_profile_by_email(email)
|
|
|
|
user_profile.is_mirror_dummy = True
|
|
|
|
user_profile.is_active = False
|
|
|
|
user_profile.save()
|
|
|
|
|
2016-11-03 21:24:54 +01:00
|
|
|
result = self.client_post('/register/', {'email': email})
|
2016-11-02 17:31:11 +01:00
|
|
|
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-02 17:31:11 +01:00
|
|
|
self.assertTrue(result["Location"].endswith(
|
2017-01-24 07:06:13 +01:00
|
|
|
"/accounts/send_confirm/%s" % (email,)))
|
2016-11-02 17:31:11 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started.", result)
|
|
|
|
# Visit the confirmation link.
|
|
|
|
from django.core.mail import outbox
|
|
|
|
for message in reversed(outbox):
|
|
|
|
if email in message.to:
|
|
|
|
confirmation_link_pattern = re.compile(settings.EXTERNAL_HOST + "(\S+)>")
|
|
|
|
confirmation_url = confirmation_link_pattern.search(
|
|
|
|
message.body).groups()[0]
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise ValueError("Couldn't find a confirmation email.")
|
|
|
|
|
|
|
|
result = self.client_get(confirmation_url)
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-11-02 17:31:11 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
from_confirmation='1',
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2017-01-04 08:53:56 +01:00
|
|
|
result = self.submit_reg_form_for_user(email,
|
2016-11-02 17:31:11 +01:00
|
|
|
password,
|
|
|
|
realm_name=realm_name,
|
|
|
|
realm_subdomain=subdomain,
|
|
|
|
# Pass HTTP_HOST for the target subdomain
|
|
|
|
HTTP_HOST=subdomain + ".testserver")
|
2016-12-16 02:01:34 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2016-11-02 17:31:11 +01:00
|
|
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
|
|
|
|
2016-10-13 20:09:32 +02:00
|
|
|
class DeactivateUserTest(ZulipTestCase):
|
|
|
|
|
|
|
|
def test_deactivate_user(self):
|
|
|
|
# type: () -> None
|
|
|
|
email = 'hamlet@zulip.com'
|
|
|
|
self.login(email)
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertTrue(user.is_active)
|
|
|
|
result = self.client_delete('/json/users/me')
|
|
|
|
self.assert_json_success(result)
|
|
|
|
user = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
self.assertFalse(user.is_active)
|
|
|
|
self.login(email, fails=True)
|
|
|
|
|
|
|
|
def test_do_not_deactivate_final_admin(self):
|
|
|
|
# type: () -> None
|
|
|
|
email = 'iago@zulip.com'
|
|
|
|
self.login(email)
|
|
|
|
user = get_user_profile_by_email('iago@zulip.com')
|
|
|
|
self.assertTrue(user.is_active)
|
2016-12-05 06:40:00 +01:00
|
|
|
result = self.client_delete('/json/users/me')
|
|
|
|
self.assert_json_error(result, "Cannot deactivate the only organization administrator")
|
2016-10-13 20:09:32 +02:00
|
|
|
user = get_user_profile_by_email('iago@zulip.com')
|
|
|
|
self.assertTrue(user.is_active)
|
|
|
|
self.assertTrue(user.is_realm_admin)
|
|
|
|
email = 'hamlet@zulip.com'
|
|
|
|
user_2 = get_user_profile_by_email('hamlet@zulip.com')
|
|
|
|
do_change_is_admin(user_2, True)
|
|
|
|
self.assertTrue(user_2.is_realm_admin)
|
|
|
|
result = self.client_delete('/json/users/me')
|
|
|
|
self.assert_json_success(result)
|
|
|
|
do_change_is_admin(user, True)
|