mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	Since do_create_realm also creates general and core team streams, we rename general to verona right after the realm is created. Mostly because we dont really want two additional streams and this might probably make it easy to review things. There are puppeteer test changes because, we have a new "core team" stream in tests as well as there is a new default notification stream "Verona". Because of this tests in message-basics for example have to be changed since the newly added core team affects the order in which we navigate through the streams using arrow keys. The extra await for selector was added in subscriptions test to make the tests wait. Without the await the tests were passing ocassionally and failing in some other times. Fixes #6967
		
			
				
	
	
		
			352 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import datetime
 | 
						|
import random
 | 
						|
from typing import Sequence
 | 
						|
from unittest import mock
 | 
						|
 | 
						|
import pytz
 | 
						|
from django.conf import settings
 | 
						|
from django.core import mail
 | 
						|
from django.test import override_settings
 | 
						|
 | 
						|
from corporate.lib.stripe import get_latest_seat_count
 | 
						|
from zerver.lib.actions import do_change_notification_settings, notify_new_user
 | 
						|
from zerver.lib.initial_password import initial_password
 | 
						|
from zerver.lib.streams import create_stream_if_needed
 | 
						|
from zerver.lib.test_classes import ZulipTestCase
 | 
						|
from zerver.models import Message, Realm, Recipient, Stream, UserProfile, get_realm
 | 
						|
from zerver.signals import JUST_CREATED_THRESHOLD, get_device_browser, get_device_os
 | 
						|
 | 
						|
 | 
						|
class SendLoginEmailTest(ZulipTestCase):
 | 
						|
    """
 | 
						|
    Uses django's user_logged_in signal to send emails on new login.
 | 
						|
 | 
						|
    The receiver handler for this signal is always registered in production,
 | 
						|
    development and testing, but emails are only sent based on SEND_LOGIN_EMAILS setting.
 | 
						|
 | 
						|
    SEND_LOGIN_EMAILS is set to true in default settings.
 | 
						|
    It is turned off during testing.
 | 
						|
    """
 | 
						|
 | 
						|
    def test_send_login_emails_if_send_login_email_setting_is_true(self) -> None:
 | 
						|
        with self.settings(SEND_LOGIN_EMAILS=True):
 | 
						|
            self.assertTrue(settings.SEND_LOGIN_EMAILS)
 | 
						|
            # we don't use the self.login method since we spoof the user-agent
 | 
						|
            mock_time = datetime.datetime(year=2018, month=1, day=1, tzinfo=datetime.timezone.utc)
 | 
						|
 | 
						|
            user = self.example_user("hamlet")
 | 
						|
            user.timezone = "US/Pacific"
 | 
						|
            user.twenty_four_hour_time = False
 | 
						|
            user.date_joined = mock_time - datetime.timedelta(seconds=JUST_CREATED_THRESHOLD + 1)
 | 
						|
            user.save()
 | 
						|
            password = initial_password(user.delivery_email)
 | 
						|
            login_info = dict(
 | 
						|
                username=user.delivery_email,
 | 
						|
                password=password,
 | 
						|
            )
 | 
						|
            firefox_windows = (
 | 
						|
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
 | 
						|
            )
 | 
						|
            user_tz = pytz.timezone(user.timezone)
 | 
						|
            mock_time = datetime.datetime(year=2018, month=1, day=1, tzinfo=datetime.timezone.utc)
 | 
						|
            reference_time = mock_time.astimezone(user_tz).strftime("%A, %B %d, %Y at %I:%M%p %Z")
 | 
						|
            with mock.patch("zerver.signals.timezone_now", return_value=mock_time):
 | 
						|
                self.client_post(
 | 
						|
                    "/accounts/login/", info=login_info, HTTP_USER_AGENT=firefox_windows
 | 
						|
                )
 | 
						|
 | 
						|
            # email is sent and correct subject
 | 
						|
            self.assert_length(mail.outbox, 1)
 | 
						|
            subject = "New login from Firefox on Windows"
 | 
						|
            self.assertEqual(mail.outbox[0].subject, subject)
 | 
						|
            # local time is correct and in email's body
 | 
						|
            self.assertIn(reference_time, mail.outbox[0].body)
 | 
						|
 | 
						|
            # Try again with the 24h time format setting enabled for this user
 | 
						|
            self.logout()  # We just logged in, we'd be redirected without this
 | 
						|
            user.twenty_four_hour_time = True
 | 
						|
            user.save()
 | 
						|
            with mock.patch("zerver.signals.timezone_now", return_value=mock_time):
 | 
						|
                self.client_post(
 | 
						|
                    "/accounts/login/", info=login_info, HTTP_USER_AGENT=firefox_windows
 | 
						|
                )
 | 
						|
 | 
						|
            reference_time = mock_time.astimezone(user_tz).strftime("%A, %B %d, %Y at %H:%M %Z")
 | 
						|
            self.assertIn(reference_time, mail.outbox[1].body)
 | 
						|
 | 
						|
    def test_dont_send_login_emails_if_send_login_emails_is_false(self) -> None:
 | 
						|
        self.assertFalse(settings.SEND_LOGIN_EMAILS)
 | 
						|
        user = self.example_user("hamlet")
 | 
						|
        self.login_user(user)
 | 
						|
 | 
						|
        self.assert_length(mail.outbox, 0)
 | 
						|
 | 
						|
    def test_dont_send_login_emails_for_new_user_registration_logins(self) -> None:
 | 
						|
        with self.settings(SEND_LOGIN_EMAILS=True):
 | 
						|
            self.register("test@zulip.com", "test")
 | 
						|
 | 
						|
            # Verify that there's just 1 email for new user registration.
 | 
						|
            self.assertEqual(mail.outbox[0].subject, "Activate your Zulip account")
 | 
						|
            self.assert_length(mail.outbox, 1)
 | 
						|
 | 
						|
    def test_without_path_info_dont_send_login_emails_for_new_user_registration_logins(
 | 
						|
        self,
 | 
						|
    ) -> None:
 | 
						|
        with self.settings(SEND_LOGIN_EMAILS=True):
 | 
						|
            self.client_post("/accounts/home/", {"email": "orange@zulip.com"})
 | 
						|
            self.submit_reg_form_for_user("orange@zulip.com", "orange", PATH_INFO="")
 | 
						|
 | 
						|
            for email in mail.outbox:
 | 
						|
                subject = "New login from an unknown browser on an unknown operating system"
 | 
						|
                self.assertNotEqual(email.subject, subject)
 | 
						|
 | 
						|
    @override_settings(SEND_LOGIN_EMAILS=True)
 | 
						|
    def test_enable_login_emails_user_setting(self) -> None:
 | 
						|
        user = self.example_user("hamlet")
 | 
						|
        mock_time = datetime.datetime(year=2018, month=1, day=1, tzinfo=datetime.timezone.utc)
 | 
						|
 | 
						|
        user.timezone = "US/Pacific"
 | 
						|
        user.date_joined = mock_time - datetime.timedelta(seconds=JUST_CREATED_THRESHOLD + 1)
 | 
						|
        user.save()
 | 
						|
 | 
						|
        do_change_notification_settings(user, "enable_login_emails", False, acting_user=None)
 | 
						|
        self.assertFalse(user.enable_login_emails)
 | 
						|
        with mock.patch("zerver.signals.timezone_now", return_value=mock_time):
 | 
						|
            self.login_user(user)
 | 
						|
        self.assert_length(mail.outbox, 0)
 | 
						|
 | 
						|
        do_change_notification_settings(user, "enable_login_emails", True, acting_user=None)
 | 
						|
        self.assertTrue(user.enable_login_emails)
 | 
						|
        with mock.patch("zerver.signals.timezone_now", return_value=mock_time):
 | 
						|
            self.login_user(user)
 | 
						|
        self.assert_length(mail.outbox, 1)
 | 
						|
 | 
						|
 | 
						|
class TestBrowserAndOsUserAgentStrings(ZulipTestCase):
 | 
						|
    def setUp(self) -> None:
 | 
						|
        super().setUp()
 | 
						|
        self.user_agents = [
 | 
						|
            (
 | 
						|
                "mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
 | 
						|
                + "Chrome/54.0.2840.59 Safari/537.36",
 | 
						|
                "Chrome",
 | 
						|
                "Linux",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "mozilla/5.0 (windows nt 6.1; win64; x64) applewebkit/537.36 (khtml, like gecko) "
 | 
						|
                + "chrome/56.0.2924.87 safari/537.36",
 | 
						|
                "Chrome",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "mozilla/5.0 (windows nt 6.1; wow64; rv:51.0) gecko/20100101 firefox/51.0",
 | 
						|
                "Firefox",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) like gecko",
 | 
						|
                "Internet Explorer",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (Android; Mobile; rv:27.0) Gecko/27.0 Firefox/27.0",
 | 
						|
                "Firefox",
 | 
						|
                "Android",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) "
 | 
						|
                "AppleWebKit/602.1.50 (KHTML, like Gecko) "
 | 
						|
                "CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1",
 | 
						|
                "Chrome",
 | 
						|
                "iOS",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (iPad; CPU OS 6_1_3 like Mac OS X) "
 | 
						|
                + "AppleWebKit/536.26 (KHTML, like Gecko) "
 | 
						|
                + "Version/6.0 Mobile/10B329 Safari/8536.25",
 | 
						|
                "Safari",
 | 
						|
                "iOS",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) "
 | 
						|
                + "AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B350",
 | 
						|
                None,
 | 
						|
                "iOS",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) "
 | 
						|
                + "AppleWebKit/537.36 (KHTML, like Gecko) "
 | 
						|
                + "Chrome/56.0.2924.87 Safari/537.36",
 | 
						|
                "Chrome",
 | 
						|
                "macOS",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) "
 | 
						|
                + "AppleWebKit/602.3.12 (KHTML, like Gecko) "
 | 
						|
                + "Version/10.0.2 Safari/602.3.12",
 | 
						|
                "Safari",
 | 
						|
                "macOS",
 | 
						|
            ),
 | 
						|
            ("ZulipAndroid/1.0", "Zulip", "Android"),
 | 
						|
            ("ZulipMobile/1.0.12 (Android 7.1.1)", "Zulip", "Android"),
 | 
						|
            ("ZulipMobile/0.7.1.1 (iOS 10.3.1)", "Zulip", "iOS"),
 | 
						|
            (
 | 
						|
                "ZulipElectron/1.1.0-beta Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
 | 
						|
                + "AppleWebKit/537.36 (KHTML, like Gecko) Zulip/1.1.0-beta "
 | 
						|
                + "Chrome/56.0.2924.87 Electron/1.6.8 Safari/537.36",
 | 
						|
                "Zulip",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, "
 | 
						|
                "like Gecko) Ubuntu/11.10 Chromium/16.0.912.77 "
 | 
						|
                "Chrome/16.0.912.77 Safari/535.7",
 | 
						|
                "Chromium",
 | 
						|
                "Linux",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 "
 | 
						|
                "(KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 "
 | 
						|
                "OPR/15.0.1147.100",
 | 
						|
                "Opera",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (Windows NT 10.0; <64-bit tags>) AppleWebKit/"
 | 
						|
                "<WebKit Rev> (KHTML, like Gecko) Chrome/<Chrome Rev> Safari"
 | 
						|
                "/<WebKit Rev> Edge/<EdgeHTML Rev>."
 | 
						|
                "<Windows Build>",
 | 
						|
                "Edge",
 | 
						|
                "Windows",
 | 
						|
            ),
 | 
						|
            (
 | 
						|
                "Mozilla/5.0 (X11; CrOS x86_64 10895.56.0) AppleWebKit/537.36"
 | 
						|
                "(KHTML, like Gecko) Chrome/69.0.3497.95 Safari/537.36",
 | 
						|
                "Chrome",
 | 
						|
                "ChromeOS",
 | 
						|
            ),
 | 
						|
            ("", None, None),
 | 
						|
        ]
 | 
						|
 | 
						|
    def test_get_browser_on_new_login(self) -> None:
 | 
						|
        for user_agent in self.user_agents:
 | 
						|
            device_browser = get_device_browser(user_agent[0])
 | 
						|
            self.assertEqual(device_browser, user_agent[1])
 | 
						|
 | 
						|
    def test_get_os_on_new_login(self) -> None:
 | 
						|
        for user_agent in self.user_agents:
 | 
						|
            device_os = get_device_os(user_agent[0])
 | 
						|
            self.assertEqual(device_os, user_agent[2])
 | 
						|
 | 
						|
 | 
						|
class TestNotifyNewUser(ZulipTestCase):
 | 
						|
    def get_message_count(self) -> int:
 | 
						|
        return Message.objects.all().count()
 | 
						|
 | 
						|
    def test_notify_realm_of_new_user(self) -> None:
 | 
						|
        realm = get_realm("zulip")
 | 
						|
        new_user = self.example_user("cordelia")
 | 
						|
        admin_realm = get_realm("zulipinternal")
 | 
						|
        admin_realm_signups_stream, created = create_stream_if_needed(admin_realm, "signups")
 | 
						|
        message_count = self.get_message_count()
 | 
						|
 | 
						|
        notify_new_user(new_user)
 | 
						|
        self.assertEqual(self.get_message_count(), message_count + 2)
 | 
						|
        message = self.get_second_to_last_message()
 | 
						|
        self.assertEqual(message.recipient.type, Recipient.STREAM)
 | 
						|
        actual_stream = Stream.objects.get(id=message.recipient.type_id)
 | 
						|
        self.assertEqual(actual_stream.name, Realm.INITIAL_PRIVATE_STREAM_NAME)
 | 
						|
        self.assertIn(
 | 
						|
            f"@_**Cordelia, Lear's daughter|{new_user.id}** just signed up for Zulip.",
 | 
						|
            message.content,
 | 
						|
        )
 | 
						|
        message = self.get_last_message()
 | 
						|
        self.assertEqual(message.recipient.type, Recipient.STREAM)
 | 
						|
        actual_stream = Stream.objects.get(id=message.recipient.type_id)
 | 
						|
        self.assertEqual(actual_stream.name, "signups")
 | 
						|
        self.assertIn(
 | 
						|
            f"Cordelia, Lear's daughter <`{new_user.email}`> just signed up for Zulip. (total:",
 | 
						|
            message.content,
 | 
						|
        )
 | 
						|
 | 
						|
        admin_realm_signups_stream.delete()
 | 
						|
        notify_new_user(new_user)
 | 
						|
        self.assertEqual(self.get_message_count(), message_count + 3)
 | 
						|
        message = self.get_last_message()
 | 
						|
        self.assertEqual(message.recipient.type, Recipient.STREAM)
 | 
						|
        actual_stream = Stream.objects.get(id=message.recipient.type_id)
 | 
						|
        self.assertEqual(actual_stream.name, Realm.INITIAL_PRIVATE_STREAM_NAME)
 | 
						|
        self.assertIn(
 | 
						|
            f"@_**Cordelia, Lear's daughter|{new_user.id}** just signed up for Zulip.",
 | 
						|
            message.content,
 | 
						|
        )
 | 
						|
        realm.signup_notifications_stream = None
 | 
						|
        realm.save(update_fields=["signup_notifications_stream"])
 | 
						|
        new_user.refresh_from_db()
 | 
						|
        notify_new_user(new_user)
 | 
						|
        self.assertEqual(self.get_message_count(), message_count + 3)
 | 
						|
 | 
						|
    def test_notify_realm_of_new_user_in_manual_license_management(self) -> None:
 | 
						|
        realm = get_realm("zulip")
 | 
						|
 | 
						|
        user_count = get_latest_seat_count(realm)
 | 
						|
        self.subscribe_realm_to_monthly_plan_on_manual_license_management(
 | 
						|
            realm, user_count + 5, user_count + 5
 | 
						|
        )
 | 
						|
 | 
						|
        def create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_present: Sequence[str] = [], strings_absent: Sequence[str] = []
 | 
						|
        ) -> None:
 | 
						|
            user_no = random.randrange(100000)
 | 
						|
            new_user = UserProfile.objects.create(
 | 
						|
                realm=realm,
 | 
						|
                full_name=f"new user {user_no}",
 | 
						|
                email=f"user-{user_no}-email@zulip.com",
 | 
						|
                delivery_email=f"user-{user_no}-delivery-email@zulip.com",
 | 
						|
            )
 | 
						|
            notify_new_user(new_user)
 | 
						|
 | 
						|
            message = self.get_last_message()
 | 
						|
            actual_stream = Stream.objects.get(id=message.recipient.type_id)
 | 
						|
            self.assertEqual(actual_stream, realm.signup_notifications_stream)
 | 
						|
            self.assertIn(
 | 
						|
                f"@_**new user {user_no}|{new_user.id}** just signed up for Zulip.",
 | 
						|
                message.content,
 | 
						|
            )
 | 
						|
            for string_present in strings_present:
 | 
						|
                self.assertIn(
 | 
						|
                    string_present,
 | 
						|
                    message.content,
 | 
						|
                )
 | 
						|
            for string_absent in strings_absent:
 | 
						|
                self.assertNotIn(string_absent, message.content)
 | 
						|
 | 
						|
        create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_absent=["Your organization has"]
 | 
						|
        )
 | 
						|
        create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_present=[
 | 
						|
                "Your organization has only three Zulip licenses remaining",
 | 
						|
                "to allow more than three users to",
 | 
						|
            ],
 | 
						|
        )
 | 
						|
        create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_present=[
 | 
						|
                "Your organization has only two Zulip licenses remaining",
 | 
						|
                "to allow more than two users to",
 | 
						|
            ],
 | 
						|
        )
 | 
						|
 | 
						|
        create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_present=[
 | 
						|
                "Your organization has only one Zulip license remaining",
 | 
						|
                "to allow more than one user to",
 | 
						|
            ],
 | 
						|
        )
 | 
						|
        create_new_user_and_verify_strings_in_notification_message(
 | 
						|
            strings_present=[
 | 
						|
                "Your organization has no Zulip licenses remaining",
 | 
						|
                "to allow new users to",
 | 
						|
            ]
 | 
						|
        )
 |