2018-01-26 21:12:58 +01:00
|
|
|
import os
|
|
|
|
import re
|
2017-02-09 22:58:43 +01:00
|
|
|
from datetime import timedelta
|
2024-07-12 02:30:23 +02:00
|
|
|
from typing import Any
|
2020-08-27 22:46:39 +02:00
|
|
|
from unittest import mock, skipUnless
|
2020-06-11 00:54:34 +02:00
|
|
|
from unittest.mock import MagicMock, call, patch
|
2023-12-05 21:14:17 +01:00
|
|
|
from urllib.parse import quote, quote_plus
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2020-08-27 22:46:39 +02:00
|
|
|
from django.apps import apps
|
2016-04-14 23:39:37 +02:00
|
|
|
from django.conf import settings
|
2020-08-27 22:46:39 +02:00
|
|
|
from django.core.management import call_command, find_commands
|
2021-07-16 22:11:10 +02:00
|
|
|
from django.core.management.base import CommandError
|
2020-07-01 04:19:54 +02:00
|
|
|
from django.test import override_settings
|
2023-10-12 19:43:45 +02:00
|
|
|
from typing_extensions import override
|
2018-01-22 21:50:22 +01:00
|
|
|
|
2016-06-22 21:16:02 +02:00
|
|
|
from confirmation.models import RealmCreationKey, generate_realm_creation_url
|
2022-04-14 23:53:15 +02:00
|
|
|
from zerver.actions.create_user import do_create_user
|
2024-09-24 06:45:34 +02:00
|
|
|
from zerver.actions.user_settings import do_change_user_setting
|
2021-07-16 22:11:10 +02:00
|
|
|
from zerver.lib.management import ZulipBaseCommand, check_config
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
|
|
from zerver.lib.test_helpers import most_recent_message, stdout_suppressed
|
2024-09-24 06:45:34 +02:00
|
|
|
from zerver.models import Realm, Recipient, UserProfile
|
2024-09-26 12:18:55 +02:00
|
|
|
from zerver.models.realms import get_realm
|
2023-12-15 03:57:04 +01:00
|
|
|
from zerver.models.streams import get_stream
|
2023-12-15 01:16:00 +01:00
|
|
|
from zerver.models.users import get_user_profile_by_email
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2018-05-04 01:04:12 +02:00
|
|
|
class TestCheckConfig(ZulipTestCase):
|
|
|
|
def test_check_config(self) -> None:
|
2020-06-08 03:24:49 +02:00
|
|
|
check_config()
|
2024-07-14 20:30:42 +02:00
|
|
|
with (
|
|
|
|
self.settings(REQUIRED_SETTINGS=[("asdf", "not asdf")]),
|
|
|
|
self.assertRaisesRegex(
|
2021-02-12 08:19:30 +01:00
|
|
|
CommandError, "Error: You must set asdf in /etc/zulip/settings.py."
|
2024-07-14 20:30:42 +02:00
|
|
|
),
|
|
|
|
):
|
|
|
|
check_config()
|
2018-05-04 01:04:12 +02:00
|
|
|
|
2018-05-14 21:01:48 +02:00
|
|
|
@override_settings(WARN_NO_EMAIL=True)
|
|
|
|
def test_check_send_email(self) -> None:
|
|
|
|
with self.assertRaisesRegex(CommandError, "Outgoing email not yet configured, see"):
|
2021-02-12 08:20:45 +01:00
|
|
|
call_command("send_test_email", "test@example.com")
|
2018-05-14 21:01:48 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2017-07-07 20:35:31 +02:00
|
|
|
class TestZulipBaseCommand(ZulipTestCase):
|
2023-10-12 19:43:45 +02:00
|
|
|
@override
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2019-10-19 20:47:00 +02:00
|
|
|
super().setUp()
|
2017-08-19 21:00:19 +02:00
|
|
|
self.zulip_realm = get_realm("zulip")
|
2017-08-25 00:12:36 +02:00
|
|
|
self.command = ZulipBaseCommand()
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2018-03-14 00:25:31 +01:00
|
|
|
def test_get_client(self) -> None:
|
|
|
|
self.assertEqual(self.command.get_client().name, "ZulipServer")
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_realm(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(self.command.get_realm(dict(realm_id="zulip")), self.zulip_realm)
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(self.command.get_realm(dict(realm_id=None)), None)
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
|
|
|
self.command.get_realm(dict(realm_id=str(self.zulip_realm.id))), self.zulip_realm
|
|
|
|
)
|
2017-08-07 21:32:10 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "There is no realm with id"):
|
2021-02-12 08:20:45 +01:00
|
|
|
self.command.get_realm(dict(realm_id="17"))
|
2017-08-07 21:32:10 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "There is no realm with id"):
|
2021-02-12 08:20:45 +01:00
|
|
|
self.command.get_realm(dict(realm_id="mit"))
|
2017-07-07 20:35:31 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_user(self) -> None:
|
2017-07-07 20:35:31 +02:00
|
|
|
mit_realm = get_realm("zephyr")
|
|
|
|
user_profile = self.example_user("hamlet")
|
2020-03-12 14:17:25 +01:00
|
|
|
email = user_profile.delivery_email
|
2017-07-07 20:35:31 +02:00
|
|
|
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(self.command.get_user(email, self.zulip_realm), user_profile)
|
|
|
|
self.assertEqual(self.command.get_user(email, None), user_profile)
|
|
|
|
|
2020-06-10 06:41:04 +02:00
|
|
|
error_message = f"The realm '{mit_realm}' does not contain a user with email"
|
2017-08-25 00:12:36 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_user(email, mit_realm)
|
|
|
|
|
2017-07-07 20:35:31 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "server does not contain a user with email"):
|
2021-02-12 08:20:45 +01:00
|
|
|
self.command.get_user("invalid_email@example.com", None)
|
2018-03-18 20:31:48 +01:00
|
|
|
|
2021-02-06 14:27:06 +01:00
|
|
|
do_create_user(email, "password", mit_realm, "full_name", acting_user=None)
|
2018-03-18 20:31:48 +01:00
|
|
|
|
|
|
|
with self.assertRaisesRegex(CommandError, "server contains multiple users with that email"):
|
|
|
|
self.command.get_user(email, None)
|
2017-07-07 20:35:31 +02:00
|
|
|
|
2018-03-17 18:11:26 +01:00
|
|
|
def test_get_user_profile_by_email(self) -> None:
|
|
|
|
user_profile = self.example_user("hamlet")
|
2020-03-12 14:17:25 +01:00
|
|
|
email = user_profile.delivery_email
|
2018-03-17 18:11:26 +01:00
|
|
|
|
|
|
|
self.assertEqual(get_user_profile_by_email(email), user_profile)
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
def get_users_sorted(
|
2024-07-12 02:30:23 +02:00
|
|
|
self, options: dict[str, Any], realm: Realm | None, **kwargs: Any
|
2024-07-12 02:30:17 +02:00
|
|
|
) -> list[UserProfile]:
|
2019-08-14 19:48:54 +02:00
|
|
|
user_profiles = self.command.get_users(options, realm, **kwargs)
|
2021-02-12 08:19:30 +01:00
|
|
|
return sorted(user_profiles, key=lambda x: x.email)
|
2017-08-25 00:12:36 +02:00
|
|
|
|
2024-07-12 02:30:17 +02:00
|
|
|
def sorted_users(self, users: list[UserProfile]) -> list[UserProfile]:
|
2021-02-12 08:19:30 +01:00
|
|
|
return sorted(users, key=lambda x: x.email)
|
2020-03-12 14:17:25 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_users(self) -> None:
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = self.sorted_users(
|
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
self.example_user("hamlet"),
|
|
|
|
self.example_user("iago"),
|
2021-02-12 08:19:30 +01:00
|
|
|
]
|
|
|
|
)
|
2020-03-12 14:17:25 +01:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
user_emails = ",".join(u.delivery_email for u in expected_user_profiles)
|
2017-08-25 00:12:36 +02:00
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), self.zulip_realm)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), None)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = self.sorted_users(
|
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
self.mit_user("sipbtest"),
|
|
|
|
self.example_user("iago"),
|
2021-02-12 08:19:30 +01:00
|
|
|
]
|
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
user_emails = ",".join(u.delivery_email for u in expected_user_profiles)
|
2017-08-25 00:12:36 +02:00
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), None)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
2020-06-10 06:41:04 +02:00
|
|
|
error_message = f"The realm '{self.zulip_realm}' does not contain a user with email"
|
2017-08-25 00:12:36 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=user_emails), self.zulip_realm)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2023-08-03 22:20:37 +02:00
|
|
|
list(self.command.get_users(dict(users=self.example_email("iago")), self.zulip_realm)),
|
2021-02-12 08:19:30 +01:00
|
|
|
[self.example_user("iago")],
|
|
|
|
)
|
2017-08-25 00:12:36 +02:00
|
|
|
|
2023-08-03 22:20:37 +02:00
|
|
|
self.assertEqual(list(self.command.get_users(dict(users=None), None)), [])
|
2017-08-25 00:12:36 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_users_with_all_users_argument_enabled(self) -> None:
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = self.sorted_users(
|
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
self.example_user("hamlet"),
|
|
|
|
self.example_user("iago"),
|
2021-02-12 08:19:30 +01:00
|
|
|
]
|
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
user_emails = ",".join(u.delivery_email for u in expected_user_profiles)
|
2021-02-12 08:19:30 +01:00
|
|
|
user_profiles = self.get_users_sorted(
|
|
|
|
dict(users=user_emails, all_users=False), self.zulip_realm
|
|
|
|
)
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
error_message = "You can't use both -u/--users and -a/--all-users."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=user_emails, all_users=True), None)
|
|
|
|
|
2019-08-14 19:48:54 +02:00
|
|
|
# Test the default mode excluding bots and deactivated users
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = sorted(
|
|
|
|
UserProfile.objects.filter(realm=self.zulip_realm, is_active=True, is_bot=False),
|
|
|
|
key=lambda x: x.email,
|
|
|
|
)
|
|
|
|
user_profiles = self.get_users_sorted(
|
|
|
|
dict(users=None, all_users=True), self.zulip_realm, is_bot=False
|
|
|
|
)
|
2019-08-14 19:48:54 +02:00
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
|
|
|
|
# Test the default mode excluding bots and deactivated users
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = sorted(
|
|
|
|
UserProfile.objects.filter(realm=self.zulip_realm, is_active=True),
|
|
|
|
key=lambda x: x.email,
|
|
|
|
)
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=None, all_users=True), self.zulip_realm)
|
2019-08-14 19:48:54 +02:00
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
|
|
|
|
# Test include_deactivated
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = sorted(
|
|
|
|
UserProfile.objects.filter(realm=self.zulip_realm, is_bot=False), key=lambda x: x.email
|
|
|
|
)
|
|
|
|
user_profiles = self.get_users_sorted(
|
|
|
|
dict(users=None, all_users=True),
|
|
|
|
self.zulip_realm,
|
|
|
|
is_bot=False,
|
|
|
|
include_deactivated=True,
|
|
|
|
)
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
|
|
|
|
error_message = "You have to pass either -u/--users or -a/--all-users."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=None, all_users=False), None)
|
|
|
|
|
|
|
|
error_message = "The --all-users option requires a realm; please pass --realm."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=None, all_users=True), None)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2019-01-11 11:25:36 +01:00
|
|
|
def test_get_non_bot_users(self) -> None:
|
2021-02-12 08:19:30 +01:00
|
|
|
expected_user_profiles = sorted(
|
|
|
|
UserProfile.objects.filter(realm=self.zulip_realm, is_bot=False), key=lambda x: x.email
|
|
|
|
)
|
|
|
|
user_profiles = self.get_users_sorted(
|
|
|
|
dict(users=None, all_users=True), self.zulip_realm, is_bot=False
|
|
|
|
)
|
2019-01-11 11:25:36 +01:00
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
class TestCommandsCanStart(ZulipTestCase):
|
2023-10-12 19:43:45 +02:00
|
|
|
@override
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2019-10-19 20:47:00 +02:00
|
|
|
super().setUp()
|
2020-06-10 07:28:15 +02:00
|
|
|
self.commands = [
|
|
|
|
command
|
2020-08-27 22:46:39 +02:00
|
|
|
for app_config in apps.get_app_configs()
|
2020-09-01 16:29:57 +02:00
|
|
|
if os.path.dirname(os.path.realpath(app_config.path)) == settings.DEPLOY_ROOT
|
2020-08-27 22:46:39 +02:00
|
|
|
for command in find_commands(os.path.join(app_config.path, "management"))
|
2020-06-10 07:28:15 +02:00
|
|
|
]
|
2020-08-27 22:46:39 +02:00
|
|
|
assert self.commands
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_management_commands_show_help(self) -> None:
|
2019-09-12 23:06:36 +02:00
|
|
|
with stdout_suppressed():
|
2017-02-09 22:58:43 +01:00
|
|
|
for command in self.commands:
|
2024-07-14 20:30:42 +02:00
|
|
|
with self.subTest(management_command=command), self.assertRaises(SystemExit):
|
|
|
|
call_command(command, "--help")
|
2017-03-24 07:55:20 +01:00
|
|
|
# zerver/management/commands/runtornado.py sets this to True;
|
|
|
|
# we need to reset it here. See #3685 for details.
|
|
|
|
settings.RUNNING_INSIDE_TORNADO = False
|
2016-04-14 23:39:37 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2020-07-01 04:19:54 +02:00
|
|
|
class TestSendWebhookFixtureMessage(ZulipTestCase):
|
2021-02-12 08:20:45 +01:00
|
|
|
COMMAND_NAME = "send_webhook_fixture_message"
|
2016-04-14 23:39:37 +02:00
|
|
|
|
2023-10-12 19:43:45 +02:00
|
|
|
@override
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2019-10-19 20:47:00 +02:00
|
|
|
super().setUp()
|
2021-02-12 08:20:45 +01:00
|
|
|
self.fixture_path = os.path.join("some", "fake", "path.json")
|
|
|
|
self.url = "/some/url/with/hook"
|
2016-04-14 23:39:37 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.Command.print_help")
|
2021-02-12 08:19:30 +01:00
|
|
|
def test_check_if_command_exits_when_fixture_param_is_empty(
|
|
|
|
self, print_help_mock: MagicMock
|
|
|
|
) -> None:
|
2019-05-03 23:20:39 +02:00
|
|
|
with self.assertRaises(CommandError):
|
2016-04-14 23:39:37 +02:00
|
|
|
call_command(self.COMMAND_NAME, url=self.url)
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
print_help_mock.assert_any_call("./manage.py", self.COMMAND_NAME)
|
2016-04-14 23:39:37 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.Command.print_help")
|
2021-02-12 08:19:30 +01:00
|
|
|
def test_check_if_command_exits_when_url_param_is_empty(
|
|
|
|
self, print_help_mock: MagicMock
|
|
|
|
) -> None:
|
2019-05-03 23:20:39 +02:00
|
|
|
with self.assertRaises(CommandError):
|
2016-04-14 23:39:37 +02:00
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path)
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
print_help_mock.assert_any_call("./manage.py", self.COMMAND_NAME)
|
2016-04-14 23:39:37 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.os.path.exists")
|
2017-11-17 07:00:53 +01:00
|
|
|
def test_check_if_command_exits_when_fixture_path_does_not_exist(
|
2021-02-12 08:19:30 +01:00
|
|
|
self, os_path_exists_mock: MagicMock
|
|
|
|
) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
os_path_exists_mock.return_value = False
|
|
|
|
|
2019-05-03 23:20:39 +02:00
|
|
|
with self.assertRaises(CommandError):
|
2016-04-14 23:39:37 +02:00
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path, url=self.url)
|
|
|
|
|
|
|
|
os_path_exists_mock.assert_any_call(os.path.join(settings.DEPLOY_ROOT, self.fixture_path))
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.os.path.exists")
|
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.Client")
|
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.orjson")
|
2016-04-14 23:39:37 +02:00
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.open", create=True)
|
2021-02-12 08:19:30 +01:00
|
|
|
def test_check_if_command_post_request_to_url_with_fixture(
|
|
|
|
self,
|
|
|
|
open_mock: MagicMock,
|
|
|
|
orjson_mock: MagicMock,
|
|
|
|
client_mock: MagicMock,
|
|
|
|
os_path_exists_mock: MagicMock,
|
|
|
|
) -> None:
|
2020-08-07 01:09:47 +02:00
|
|
|
orjson_mock.loads.return_value = {}
|
|
|
|
orjson_mock.dumps.return_value = b"{}"
|
2016-04-14 23:39:37 +02:00
|
|
|
os_path_exists_mock.return_value = True
|
|
|
|
|
|
|
|
client = client_mock()
|
|
|
|
|
2019-05-03 23:20:39 +02:00
|
|
|
with self.assertRaises(CommandError):
|
2017-10-20 18:16:38 +02:00
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path, url=self.url)
|
2020-08-07 01:09:47 +02:00
|
|
|
self.assertTrue(orjson_mock.dumps.called)
|
|
|
|
self.assertTrue(orjson_mock.loads.called)
|
2016-04-14 23:39:37 +02:00
|
|
|
self.assertTrue(open_mock.called)
|
2021-02-12 08:19:30 +01:00
|
|
|
client.post.assert_called_once_with(
|
|
|
|
self.url, b"{}", content_type="application/json", HTTP_HOST="zulip.testserver"
|
|
|
|
)
|
|
|
|
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class TestGenerateRealmCreationLink(ZulipTestCase):
|
2016-06-22 21:16:02 +02:00
|
|
|
COMMAND_NAME = "generate_realm_creation_link"
|
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_generate_link_and_create_realm(self) -> None:
|
2016-06-22 21:16:02 +02:00
|
|
|
email = "user1@test.com"
|
2018-01-29 19:58:52 +01:00
|
|
|
generated_link = generate_realm_creation_url(by_admin=True)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Get realm creation page
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(generated_link)
|
2020-04-09 21:51:58 +02:00
|
|
|
self.assert_in_success_response(["Create a new Zulip organization"], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Enter email
|
2019-05-04 04:47:44 +02:00
|
|
|
with self.assertRaises(Realm.DoesNotExist):
|
2021-02-12 08:20:45 +01:00
|
|
|
get_realm("test")
|
2023-03-03 11:58:00 +01:00
|
|
|
result = self.client_post(
|
|
|
|
generated_link,
|
|
|
|
{
|
|
|
|
"email": email,
|
|
|
|
"realm_name": "Zulip test",
|
|
|
|
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
2023-09-12 21:58:58 +02:00
|
|
|
"realm_default_language": "en",
|
2023-06-07 04:24:01 +02:00
|
|
|
"realm_subdomain": "custom-test",
|
2023-03-03 11:58:00 +01:00
|
|
|
},
|
|
|
|
)
|
2018-01-26 21:15:51 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertTrue(re.search(r"/accounts/do_confirm/\w+$", result["Location"]))
|
2018-01-26 21:19:20 +01:00
|
|
|
|
|
|
|
# Bypass sending mail for confirmation, go straight to creation form
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(result["Location"])
|
2023-02-24 09:08:26 +01:00
|
|
|
self.assert_in_response('action="/realm/register/"', result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Original link is now dead
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(generated_link)
|
2022-10-20 22:15:49 +02:00
|
|
|
self.assert_in_success_response(["Organization creation link expired or invalid"], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2018-01-26 21:12:58 +01:00
|
|
|
def test_generate_link_confirm_email(self) -> None:
|
|
|
|
email = "user1@test.com"
|
2023-04-26 16:30:25 +02:00
|
|
|
realm_name = "Zulip test"
|
2023-06-07 04:24:01 +02:00
|
|
|
string_id = "custom-test"
|
2018-01-26 21:12:58 +01:00
|
|
|
generated_link = generate_realm_creation_url(by_admin=False)
|
|
|
|
|
2023-03-03 11:58:00 +01:00
|
|
|
result = self.client_post(
|
|
|
|
generated_link,
|
|
|
|
{
|
|
|
|
"email": email,
|
2023-04-26 16:30:25 +02:00
|
|
|
"realm_name": realm_name,
|
2023-03-03 11:58:00 +01:00
|
|
|
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
2023-09-12 21:58:58 +02:00
|
|
|
"realm_default_language": "en",
|
2023-04-26 16:30:25 +02:00
|
|
|
"realm_subdomain": string_id,
|
2023-03-03 11:58:00 +01:00
|
|
|
},
|
|
|
|
)
|
2018-01-26 21:15:51 +01:00
|
|
|
self.assertEqual(result.status_code, 302)
|
2023-01-20 08:22:48 +01:00
|
|
|
self.assertEqual(
|
2023-12-05 21:14:17 +01:00
|
|
|
f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}",
|
2023-04-26 12:27:30 +02:00
|
|
|
result["Location"],
|
2023-01-20 08:22:48 +01:00
|
|
|
)
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(result["Location"])
|
2023-06-08 16:06:06 +02:00
|
|
|
self.assert_in_response("check your email", result)
|
2018-01-26 21:12:58 +01:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
# Original link is now dead
|
|
|
|
result = self.client_get(generated_link)
|
2022-10-20 22:15:49 +02:00
|
|
|
self.assert_in_success_response(["Organization creation link expired or invalid"], result)
|
2018-01-26 21:12:58 +01:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_realm_creation_with_random_link(self) -> None:
|
2018-01-26 21:15:51 +01:00
|
|
|
# Realm creation attempt with an invalid link should fail
|
2018-02-28 16:41:21 +01:00
|
|
|
random_link = "/new/5e89081eb13984e0f3b130bf7a4121d153f1614b"
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(random_link)
|
2022-10-20 22:15:49 +02:00
|
|
|
self.assert_in_success_response(["Organization creation link expired or invalid"], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_realm_creation_with_expired_link(self) -> None:
|
2018-01-26 21:15:51 +01:00
|
|
|
generated_link = generate_realm_creation_url(by_admin=True)
|
|
|
|
key = generated_link[-24:]
|
|
|
|
# Manually expire the link by changing the date of creation
|
|
|
|
obj = RealmCreationKey.objects.get(creation_key=key)
|
2024-07-14 21:06:04 +02:00
|
|
|
obj.date_created -= timedelta(days=settings.REALM_CREATION_LINK_VALIDITY_DAYS + 1)
|
2018-01-26 21:15:51 +01:00
|
|
|
obj.save()
|
|
|
|
|
|
|
|
result = self.client_get(generated_link)
|
2022-10-20 22:15:49 +02:00
|
|
|
self.assert_in_success_response(["Organization creation link expired or invalid"], result)
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2018-01-22 21:50:22 +01:00
|
|
|
|
2020-08-27 22:46:39 +02:00
|
|
|
@skipUnless(settings.ZILENCER_ENABLED, "requires zilencer")
|
2018-01-22 21:50:22 +01:00
|
|
|
class TestCalculateFirstVisibleMessageID(ZulipTestCase):
|
2021-02-12 08:20:45 +01:00
|
|
|
COMMAND_NAME = "calculate_first_visible_message_id"
|
2018-01-22 21:50:22 +01:00
|
|
|
|
|
|
|
def test_check_if_command_calls_maybe_update_first_visible_message_id(self) -> None:
|
2019-05-08 10:05:44 +02:00
|
|
|
func_name = "zilencer.management.commands.calculate_first_visible_message_id.maybe_update_first_visible_message_id"
|
|
|
|
with patch(func_name) as m:
|
2018-01-22 21:50:22 +01:00
|
|
|
call_command(self.COMMAND_NAME, "--realm=zulip", "--lookback-hours=30")
|
|
|
|
m.assert_called_with(get_realm("zulip"), 30)
|
|
|
|
|
2019-05-08 10:05:44 +02:00
|
|
|
with patch(func_name) as m:
|
2018-01-22 21:50:22 +01:00
|
|
|
call_command(self.COMMAND_NAME, "--lookback-hours=35")
|
|
|
|
calls = [call(realm, 35) for realm in Realm.objects.all()]
|
2020-08-29 00:54:27 +02:00
|
|
|
m.assert_has_calls(calls, any_order=True)
|
2018-08-23 11:02:47 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2018-08-23 11:02:47 +02:00
|
|
|
class TestPasswordRestEmail(ZulipTestCase):
|
|
|
|
COMMAND_NAME = "send_password_reset_email"
|
|
|
|
|
|
|
|
def test_if_command_sends_password_reset_email(self) -> None:
|
|
|
|
call_command(self.COMMAND_NAME, users=self.example_email("iago"))
|
|
|
|
from django.core.mail import outbox
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2021-01-26 04:20:36 +01:00
|
|
|
self.assertEqual(self.email_envelope_from(outbox[0]), settings.NOREPLY_EMAIL_ADDRESS)
|
2020-06-05 23:26:35 +02:00
|
|
|
self.assertRegex(
|
2021-01-26 04:20:36 +01:00
|
|
|
self.email_display_from(outbox[0]),
|
2022-12-24 17:31:48 +01:00
|
|
|
rf"^testserver account security <{self.TOKENIZED_NOREPLY_REGEX}>\Z",
|
2020-06-05 23:26:35 +02:00
|
|
|
)
|
2018-12-20 09:44:18 +01:00
|
|
|
self.assertIn("reset your password", outbox[0].body)
|
2018-11-12 14:15:49 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2018-11-12 14:15:49 +01:00
|
|
|
class TestRealmReactivationEmail(ZulipTestCase):
|
|
|
|
COMMAND_NAME = "send_realm_reactivation_email"
|
|
|
|
|
|
|
|
def test_if_realm_not_deactivated(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
realm = get_realm("zulip")
|
2020-06-10 06:41:04 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, f"The realm {realm.name} is already active."):
|
2018-11-12 14:15:49 +01:00
|
|
|
call_command(self.COMMAND_NAME, "--realm=zulip")
|
2019-01-09 12:27:29 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2019-01-09 12:27:29 +01:00
|
|
|
class TestSendToEmailMirror(ZulipTestCase):
|
|
|
|
COMMAND_NAME = "send_to_email_mirror"
|
|
|
|
|
|
|
|
def test_sending_a_fixture(self) -> None:
|
|
|
|
fixture_path = "zerver/tests/fixtures/email/1.txt"
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("hamlet")
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2019-01-09 12:27:29 +01:00
|
|
|
self.subscribe(user_profile, "Denmark")
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
with self.assertLogs("zerver.lib.email_mirror", level="INFO") as info_log:
|
2020-07-19 23:35:06 +02:00
|
|
|
call_command(self.COMMAND_NAME, f"--fixture={fixture_path}")
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
|
|
|
info_log.output,
|
2021-02-12 08:20:45 +01:00
|
|
|
["INFO:zerver.lib.email_mirror:Successfully processed email to Denmark (zulip)"],
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2019-01-09 12:27:29 +01:00
|
|
|
message = most_recent_message(user_profile)
|
|
|
|
|
|
|
|
# last message should be equal to the body of the email in 1.txt
|
|
|
|
self.assertEqual(message.content, "Email fixture 1.txt body")
|
|
|
|
|
|
|
|
def test_sending_a_json_fixture(self) -> None:
|
|
|
|
fixture_path = "zerver/tests/fixtures/email/1.json"
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("hamlet")
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2019-01-09 12:27:29 +01:00
|
|
|
self.subscribe(user_profile, "Denmark")
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
with self.assertLogs("zerver.lib.email_mirror", level="INFO") as info_log:
|
2020-07-19 23:35:06 +02:00
|
|
|
call_command(self.COMMAND_NAME, f"--fixture={fixture_path}")
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
|
|
|
info_log.output,
|
2021-02-12 08:20:45 +01:00
|
|
|
["INFO:zerver.lib.email_mirror:Successfully processed email to Denmark (zulip)"],
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2019-01-09 12:27:29 +01:00
|
|
|
message = most_recent_message(user_profile)
|
|
|
|
|
|
|
|
# last message should be equal to the body of the email in 1.json
|
|
|
|
self.assertEqual(message.content, "Email fixture 1.json body")
|
|
|
|
|
|
|
|
def test_stream_option(self) -> None:
|
|
|
|
fixture_path = "zerver/tests/fixtures/email/1.txt"
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("hamlet")
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2019-01-09 12:27:29 +01:00
|
|
|
self.subscribe(user_profile, "Denmark2")
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
with self.assertLogs("zerver.lib.email_mirror", level="INFO") as info_log:
|
2020-07-19 23:35:06 +02:00
|
|
|
call_command(self.COMMAND_NAME, f"--fixture={fixture_path}", "--stream=Denmark2")
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
|
|
|
info_log.output,
|
2021-02-12 08:20:45 +01:00
|
|
|
["INFO:zerver.lib.email_mirror:Successfully processed email to Denmark2 (zulip)"],
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2019-01-09 12:27:29 +01:00
|
|
|
message = most_recent_message(user_profile)
|
|
|
|
|
|
|
|
# last message should be equal to the body of the email in 1.txt
|
|
|
|
self.assertEqual(message.content, "Email fixture 1.txt body")
|
|
|
|
|
2019-07-15 22:59:18 +02:00
|
|
|
stream_id = get_stream("Denmark2", get_realm("zulip")).id
|
2019-01-09 12:27:29 +01:00
|
|
|
self.assertEqual(message.recipient.type, Recipient.STREAM)
|
|
|
|
self.assertEqual(message.recipient.type_id, stream_id)
|
2019-04-04 13:16:02 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2019-04-04 13:16:02 +02:00
|
|
|
class TestConvertMattermostData(ZulipTestCase):
|
2021-02-12 08:20:45 +01:00
|
|
|
COMMAND_NAME = "convert_mattermost_data"
|
2019-04-04 13:16:02 +02:00
|
|
|
|
2019-04-26 13:25:52 +02:00
|
|
|
def test_if_command_calls_do_convert_data(self) -> None:
|
2024-07-12 02:30:32 +02:00
|
|
|
with (
|
|
|
|
patch("zerver.management.commands.convert_mattermost_data.do_convert_data") as m,
|
|
|
|
patch("builtins.print") as mock_print,
|
|
|
|
):
|
2019-04-04 13:16:02 +02:00
|
|
|
mm_fixtures = self.fixture_file_name("", "mattermost_fixtures")
|
|
|
|
output_dir = self.make_import_output_dir("mattermost")
|
2020-06-09 00:25:09 +02:00
|
|
|
call_command(self.COMMAND_NAME, mm_fixtures, f"--output={output_dir}")
|
2019-04-04 13:16:02 +02:00
|
|
|
|
|
|
|
m.assert_called_with(
|
|
|
|
masking_content=False,
|
|
|
|
mattermost_data_dir=os.path.realpath(mm_fixtures),
|
|
|
|
output_dir=os.path.realpath(output_dir),
|
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(mock_print.mock_calls, [call("Converting data ...")])
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2019-04-26 13:15:11 +02:00
|
|
|
|
2020-08-27 22:46:39 +02:00
|
|
|
@skipUnless(settings.ZILENCER_ENABLED, "requires zilencer")
|
2019-04-26 13:15:11 +02:00
|
|
|
class TestInvoicePlans(ZulipTestCase):
|
2021-02-12 08:20:45 +01:00
|
|
|
COMMAND_NAME = "invoice_plans"
|
2019-04-26 13:15:11 +02:00
|
|
|
|
|
|
|
def test_if_command_calls_invoice_plans_as_needed(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
with patch("zilencer.management.commands.invoice_plans.invoice_plans_as_needed") as m:
|
2019-04-26 13:15:11 +02:00
|
|
|
call_command(self.COMMAND_NAME)
|
|
|
|
|
|
|
|
m.assert_called_once()
|
2019-05-10 14:28:38 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2021-06-11 12:53:45 +02:00
|
|
|
@skipUnless(settings.ZILENCER_ENABLED, "requires zilencer")
|
|
|
|
class TestDowngradeSmallRealmsBehindOnPayments(ZulipTestCase):
|
|
|
|
COMMAND_NAME = "downgrade_small_realms_behind_on_payments"
|
|
|
|
|
|
|
|
def test_if_command_calls_downgrade_small_realms_behind_on_payments_as_needed(self) -> None:
|
|
|
|
with patch(
|
|
|
|
"zilencer.management.commands.downgrade_small_realms_behind_on_payments.downgrade_small_realms_behind_on_payments_as_needed"
|
|
|
|
) as m:
|
|
|
|
call_command(self.COMMAND_NAME)
|
|
|
|
|
|
|
|
m.assert_called_once()
|
|
|
|
|
|
|
|
|
2019-05-10 14:28:38 +02:00
|
|
|
class TestExport(ZulipTestCase):
|
2021-02-12 08:20:45 +01:00
|
|
|
COMMAND_NAME = "export"
|
2019-05-10 14:28:38 +02:00
|
|
|
|
2024-09-24 06:45:34 +02:00
|
|
|
def test_command_to_export_full_with_consent(self) -> None:
|
|
|
|
do_change_user_setting(
|
|
|
|
self.example_user("iago"), "allow_private_data_export", True, acting_user=None
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2024-09-24 06:45:34 +02:00
|
|
|
do_change_user_setting(
|
|
|
|
self.example_user("iago"), "allow_private_data_export", True, acting_user=None
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2019-05-10 14:28:38 +02:00
|
|
|
|
2024-07-12 02:30:32 +02:00
|
|
|
with (
|
|
|
|
patch("zerver.management.commands.export.export_realm_wrapper") as m,
|
|
|
|
patch("builtins.print") as mock_print,
|
|
|
|
):
|
2024-09-24 06:45:34 +02:00
|
|
|
call_command(self.COMMAND_NAME, "-r=zulip", "--export-full-with-consent")
|
2021-02-12 08:19:30 +01:00
|
|
|
m.assert_called_once_with(
|
2024-09-26 12:18:55 +02:00
|
|
|
export_row=mock.ANY,
|
2021-02-12 08:19:30 +01:00
|
|
|
threads=mock.ANY,
|
|
|
|
output_dir=mock.ANY,
|
|
|
|
percent_callback=mock.ANY,
|
|
|
|
upload=False,
|
2023-04-03 16:06:10 +02:00
|
|
|
export_as_active=None,
|
2021-02-12 08:19:30 +01:00
|
|
|
)
|
2020-07-21 22:48:16 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
|
|
|
mock_print.mock_calls,
|
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
call("\033[94mExporting realm\033[0m: zulip"),
|
2021-02-12 08:19:30 +01:00
|
|
|
],
|
|
|
|
)
|
2021-04-07 01:27:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestSendCustomEmail(ZulipTestCase):
|
|
|
|
COMMAND_NAME = "send_custom_email"
|
|
|
|
|
|
|
|
def test_custom_email_with_dry_run(self) -> None:
|
|
|
|
path = "templates/zerver/tests/markdown/test_nested_code_blocks.md"
|
|
|
|
user = self.example_user("hamlet")
|
2023-08-03 22:20:37 +02:00
|
|
|
other_user = self.example_user("cordelia")
|
2021-04-07 01:27:02 +02:00
|
|
|
|
|
|
|
with patch("builtins.print") as mock_print:
|
|
|
|
call_command(
|
|
|
|
self.COMMAND_NAME,
|
|
|
|
"-r=zulip",
|
|
|
|
f"--path={path}",
|
|
|
|
f"-u={user.delivery_email}",
|
|
|
|
"--subject=Test email",
|
2022-08-27 19:16:55 +02:00
|
|
|
"--from-name=zulip@zulip.example.com",
|
2021-04-07 01:27:02 +02:00
|
|
|
"--dry-run",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
mock_print.mock_calls[1:],
|
|
|
|
[
|
|
|
|
call("Would send the above email to:"),
|
2021-04-28 01:25:56 +02:00
|
|
|
call(" hamlet@zulip.com (zulip)"),
|
2021-04-07 01:27:02 +02:00
|
|
|
],
|
|
|
|
)
|
2023-08-03 22:20:37 +02:00
|
|
|
|
|
|
|
with patch("builtins.print") as mock_print:
|
|
|
|
call_command(
|
|
|
|
self.COMMAND_NAME,
|
|
|
|
"-r=zulip",
|
|
|
|
f"--path={path}",
|
|
|
|
f"-u={user.delivery_email},{other_user.delivery_email}",
|
|
|
|
"--subject=Test email",
|
|
|
|
"--from-name=zulip@zulip.example.com",
|
|
|
|
"--dry-run",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
mock_print.mock_calls[1:],
|
|
|
|
[
|
|
|
|
call("Would send the above email to:"),
|
|
|
|
call(" cordelia@zulip.com (zulip)"),
|
|
|
|
call(" hamlet@zulip.com (zulip)"),
|
|
|
|
],
|
|
|
|
)
|