2017-03-25 21:23:54 +01:00
|
|
|
import datetime
|
2019-09-13 01:15:53 +02:00
|
|
|
import lxml.html
|
2017-03-08 11:57:55 +01:00
|
|
|
import ujson
|
|
|
|
|
2020-01-14 18:19:35 +01:00
|
|
|
from django.conf import settings
|
2017-03-08 11:57:55 +01:00
|
|
|
from django.http import HttpResponse
|
2019-01-31 22:58:28 +01:00
|
|
|
from django.utils.timezone import now as timezone_now
|
2017-03-25 21:23:54 +01:00
|
|
|
from mock import MagicMock, patch
|
2017-11-05 05:30:31 +01:00
|
|
|
import urllib
|
2019-02-02 23:53:44 +01:00
|
|
|
from typing import Any, Dict
|
2020-01-13 18:47:30 +01:00
|
|
|
from zerver.lib.actions import (
|
|
|
|
do_create_user, do_change_logo_source
|
|
|
|
)
|
2019-03-02 18:23:57 +01:00
|
|
|
from zerver.lib.events import add_realm_logo_fields
|
2017-03-08 11:57:55 +01:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2017-07-16 09:41:38 +02:00
|
|
|
from zerver.lib.test_helpers import (
|
2019-07-17 07:27:20 +02:00
|
|
|
queries_captured, get_user_messages
|
2017-07-16 09:41:38 +02:00
|
|
|
)
|
|
|
|
from zerver.lib.soft_deactivation import do_soft_deactivate_users
|
2017-03-08 11:57:55 +01:00
|
|
|
from zerver.lib.test_runner import slow
|
2020-01-13 18:47:30 +01:00
|
|
|
from zerver.lib.users import compute_show_invites_and_add_streams
|
2017-07-16 09:41:38 +02:00
|
|
|
from zerver.models import (
|
2019-02-02 23:53:44 +01:00
|
|
|
get_realm, get_stream, get_user, UserProfile,
|
2017-10-21 19:42:11 +02:00
|
|
|
flush_per_request_caches, DefaultStream, Realm,
|
2020-04-28 07:29:08 +02:00
|
|
|
get_system_bot,
|
2017-07-16 09:41:38 +02:00
|
|
|
)
|
2019-07-17 07:27:20 +02:00
|
|
|
from zerver.views.home import sent_time_in_epoch_seconds, compute_navbar_logo_url
|
2019-01-31 22:58:28 +01:00
|
|
|
from corporate.models import Customer, CustomerPlan
|
2017-03-08 11:57:55 +01:00
|
|
|
|
|
|
|
class HomeTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_home(self) -> None:
|
2017-03-08 11:57:55 +01:00
|
|
|
|
|
|
|
# Keep this list sorted!!!
|
|
|
|
html_bits = [
|
|
|
|
'Compose your message here...',
|
|
|
|
'Exclude messages with topic',
|
|
|
|
'Keyboard shortcuts',
|
|
|
|
'Loading...',
|
|
|
|
'Manage streams',
|
2019-05-15 04:39:22 +02:00
|
|
|
'Narrow to topic',
|
2017-03-08 11:57:55 +01:00
|
|
|
'Next message',
|
|
|
|
'Search streams',
|
|
|
|
'Welcome to Zulip',
|
2018-05-02 15:28:58 +02:00
|
|
|
# Verify that the app styles get included
|
2018-05-28 08:09:49 +02:00
|
|
|
'app-stubentry.js',
|
2019-09-13 01:15:53 +02:00
|
|
|
'data-params',
|
2017-03-08 11:57:55 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
# Keep this list sorted!!!
|
|
|
|
expected_keys = [
|
|
|
|
"alert_words",
|
2018-01-11 21:36:11 +01:00
|
|
|
"available_notification_sounds",
|
2017-03-08 11:57:55 +01:00
|
|
|
"avatar_source",
|
|
|
|
"avatar_url",
|
|
|
|
"avatar_url_medium",
|
2017-11-22 23:58:58 +01:00
|
|
|
"bot_types",
|
2017-03-08 11:57:55 +01:00
|
|
|
"can_create_streams",
|
2018-08-13 00:46:29 +02:00
|
|
|
"can_subscribe_other_users",
|
2017-03-08 11:57:55 +01:00
|
|
|
"cross_realm_bots",
|
2017-12-14 05:49:19 +01:00
|
|
|
"custom_profile_field_types",
|
2017-05-14 07:49:35 +02:00
|
|
|
"custom_profile_fields",
|
2017-03-08 11:57:55 +01:00
|
|
|
"debug_mode",
|
|
|
|
"default_language",
|
|
|
|
"default_language_name",
|
2018-07-16 09:07:16 +02:00
|
|
|
"delivery_email",
|
2019-03-17 14:48:51 +01:00
|
|
|
"demote_inactive_streams",
|
2018-05-24 20:53:26 +02:00
|
|
|
"dense_mode",
|
2019-06-29 22:00:44 +02:00
|
|
|
"desktop_icon_count_display",
|
2017-03-08 11:57:55 +01:00
|
|
|
"development_environment",
|
|
|
|
"email",
|
2017-04-02 21:05:33 +02:00
|
|
|
"emojiset",
|
|
|
|
"emojiset_choices",
|
2017-04-29 08:13:47 +02:00
|
|
|
"enable_desktop_notifications",
|
2017-03-08 11:57:55 +01:00
|
|
|
"enable_digest_emails",
|
2018-08-24 07:28:51 +02:00
|
|
|
"enable_login_emails",
|
2017-03-08 11:57:55 +01:00
|
|
|
"enable_offline_email_notifications",
|
|
|
|
"enable_offline_push_notifications",
|
|
|
|
"enable_online_push_notifications",
|
2017-04-29 06:53:28 +02:00
|
|
|
"enable_sounds",
|
2019-06-11 08:47:49 +02:00
|
|
|
"enable_stream_audible_notifications",
|
2017-04-29 07:01:46 +02:00
|
|
|
"enable_stream_desktop_notifications",
|
2017-11-21 04:34:01 +01:00
|
|
|
"enable_stream_email_notifications",
|
2017-08-17 16:55:32 +02:00
|
|
|
"enable_stream_push_notifications",
|
2017-03-08 11:57:55 +01:00
|
|
|
"enter_sends",
|
|
|
|
"first_in_realm",
|
2019-04-16 18:46:17 +02:00
|
|
|
"fluid_layout_width",
|
2017-04-27 00:26:49 +02:00
|
|
|
"full_name",
|
2017-03-08 11:57:55 +01:00
|
|
|
"furthest_read_time",
|
|
|
|
"has_mobile_devices",
|
|
|
|
"have_initial_messages",
|
2017-07-07 18:15:10 +02:00
|
|
|
"high_contrast_mode",
|
2017-01-24 01:48:35 +01:00
|
|
|
"hotspots",
|
2017-03-08 11:57:55 +01:00
|
|
|
"initial_servertime",
|
2020-02-28 09:55:29 +01:00
|
|
|
"insecure_desktop_app",
|
2017-03-08 11:57:55 +01:00
|
|
|
"is_admin",
|
2018-06-08 14:43:27 +02:00
|
|
|
"is_guest",
|
2018-04-03 01:46:55 +02:00
|
|
|
"jitsi_server_url",
|
2017-03-08 11:57:55 +01:00
|
|
|
"language_list",
|
|
|
|
"language_list_dbl_col",
|
|
|
|
"last_event_id",
|
|
|
|
"left_side_userlist",
|
|
|
|
"login_page",
|
|
|
|
"max_avatar_file_size",
|
2019-05-03 17:55:04 +02:00
|
|
|
"max_file_upload_size",
|
2017-03-08 11:57:55 +01:00
|
|
|
"max_icon_file_size",
|
2018-08-16 01:26:55 +02:00
|
|
|
"max_logo_file_size",
|
2017-03-08 11:57:55 +01:00
|
|
|
"max_message_id",
|
2017-11-29 13:42:39 +01:00
|
|
|
"message_content_in_email_notifications",
|
2017-03-08 11:57:55 +01:00
|
|
|
"muted_topics",
|
|
|
|
"narrow",
|
|
|
|
"narrow_stream",
|
|
|
|
"needs_tutorial",
|
2017-04-21 07:53:21 +02:00
|
|
|
"never_subscribed",
|
2017-11-14 20:42:31 +01:00
|
|
|
"night_mode",
|
2018-01-11 21:36:11 +01:00
|
|
|
"notification_sound",
|
passwords: Express the quality threshold as guesses required.
The original "quality score" was invented purely for populating
our password-strength progress bar, and isn't expressed in terms
that are particularly meaningful. For configuration and the core
accept/reject logic, it's better to use units that are readily
understood. Switch to those.
I considered using "bits of entropy", defined loosely as the log
of this number, but both the zxcvbn paper and the linked CACM
article (which I recommend!) are written in terms of the number
of guesses. And reading (most of) those two papers made me
less happy about referring to "entropy" in our terminology.
I already knew that notion was a little fuzzy if looked at
too closely, and I gained a better appreciation of how it's
contributed to confusion in discussing password policies and
to adoption of perverse policies that favor "Password1!" over
"derived unusual ravioli raft". So, "guesses" it is.
And although the log is handy for some analysis purposes
(certainly for a graph like those in the zxcvbn paper), it adds
a layer of abstraction, and I think makes it harder to think
clearly about attacks, especially in the online setting. So
just use the actual number, and if someone wants to set a
gigantic value, they will have the pleasure of seeing just
how many digits are involved.
(Thanks to @YJDave for a prototype that the code changes in this
commit are based on.)
2017-10-03 19:48:06 +02:00
|
|
|
"password_min_guesses",
|
2017-07-06 22:32:29 +02:00
|
|
|
"password_min_length",
|
2019-06-12 08:56:28 +02:00
|
|
|
"plan_includes_wide_organization_logo",
|
2017-03-08 11:57:55 +01:00
|
|
|
"pm_content_in_desktop_notifications",
|
2017-04-24 21:33:48 +02:00
|
|
|
"pointer",
|
2017-03-08 11:57:55 +01:00
|
|
|
"poll_timeout",
|
2017-04-24 21:23:50 +02:00
|
|
|
"presences",
|
2017-03-08 11:57:55 +01:00
|
|
|
"prompt_for_invites",
|
2017-04-24 21:40:16 +02:00
|
|
|
"queue_id",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_add_emoji_by_admins_only",
|
2017-12-03 00:50:48 +01:00
|
|
|
"realm_allow_community_topic_editing",
|
2017-07-16 11:00:44 +02:00
|
|
|
"realm_allow_edit_history",
|
2017-11-08 13:40:46 +01:00
|
|
|
"realm_allow_message_deleting",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_allow_message_editing",
|
|
|
|
"realm_authentication_methods",
|
2018-04-23 14:51:30 +02:00
|
|
|
"realm_available_video_chat_providers",
|
2019-04-23 04:51:04 +02:00
|
|
|
"realm_avatar_changes_disabled",
|
2018-01-29 16:10:54 +01:00
|
|
|
"realm_bot_creation_policy",
|
2017-03-05 04:17:12 +01:00
|
|
|
"realm_bot_domain",
|
2017-04-21 08:24:30 +02:00
|
|
|
"realm_bots",
|
2019-05-06 16:34:31 +02:00
|
|
|
"realm_create_stream_policy",
|
2020-03-31 15:21:27 +02:00
|
|
|
"realm_default_code_block_language",
|
2019-05-27 10:59:55 +02:00
|
|
|
"realm_default_external_accounts",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_default_language",
|
2017-11-01 18:20:34 +01:00
|
|
|
"realm_default_stream_groups",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_default_streams",
|
2018-03-30 22:38:16 +02:00
|
|
|
"realm_default_twenty_four_hour_time",
|
2017-03-18 20:19:44 +01:00
|
|
|
"realm_description",
|
2018-08-01 12:51:35 +02:00
|
|
|
"realm_digest_emails_enabled",
|
2019-03-31 12:13:42 +02:00
|
|
|
"realm_digest_weekday",
|
2018-03-05 20:19:07 +01:00
|
|
|
"realm_disallow_disposable_email_addresses",
|
2017-04-20 07:30:51 +02:00
|
|
|
"realm_domains",
|
2018-12-07 00:48:06 +01:00
|
|
|
"realm_email_address_visibility",
|
2017-10-24 20:59:11 +02:00
|
|
|
"realm_email_auth_enabled",
|
2017-03-13 18:41:27 +01:00
|
|
|
"realm_email_changes_disabled",
|
2018-07-27 23:26:29 +02:00
|
|
|
"realm_emails_restricted_to_domains",
|
2017-10-19 16:25:06 +02:00
|
|
|
"realm_embedded_bots",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_emoji",
|
|
|
|
"realm_filters",
|
2018-04-23 14:51:30 +02:00
|
|
|
"realm_google_hangouts_domain",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_icon_source",
|
|
|
|
"realm_icon_url",
|
2019-08-18 15:09:18 +02:00
|
|
|
"realm_incoming_webhook_bots",
|
2017-03-13 14:42:03 +01:00
|
|
|
"realm_inline_image_preview",
|
|
|
|
"realm_inline_url_embed_preview",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_invite_by_admins_only",
|
|
|
|
"realm_invite_required",
|
2019-04-08 19:23:00 +02:00
|
|
|
"realm_invite_to_stream_policy",
|
2017-04-20 08:03:44 +02:00
|
|
|
"realm_is_zephyr_mirror_realm",
|
2018-08-16 01:26:55 +02:00
|
|
|
"realm_logo_source",
|
|
|
|
"realm_logo_url",
|
2017-04-20 07:50:34 +02:00
|
|
|
"realm_mandatory_topics",
|
2019-01-14 14:04:08 +01:00
|
|
|
"realm_message_content_allowed_in_email_notifications",
|
2017-11-26 09:12:10 +01:00
|
|
|
"realm_message_content_delete_limit_seconds",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_message_content_edit_limit_seconds",
|
2016-11-30 10:42:58 +01:00
|
|
|
"realm_message_retention_days",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_name",
|
2017-03-13 18:33:49 +01:00
|
|
|
"realm_name_changes_disabled",
|
2018-01-06 23:30:43 +01:00
|
|
|
"realm_name_in_notifications",
|
2019-01-27 08:25:10 +01:00
|
|
|
"realm_night_logo_source",
|
|
|
|
"realm_night_logo_url",
|
2017-10-21 18:36:09 +02:00
|
|
|
"realm_non_active_users",
|
2017-05-17 03:48:47 +02:00
|
|
|
"realm_notifications_stream_id",
|
2017-04-20 08:21:31 +02:00
|
|
|
"realm_password_auth_enabled",
|
2019-01-16 09:33:17 +01:00
|
|
|
"realm_plan_type",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_presence_disabled",
|
2020-01-08 01:49:44 +01:00
|
|
|
"realm_private_message_policy",
|
2018-05-08 20:45:13 +02:00
|
|
|
"realm_push_notifications_enabled",
|
2018-02-18 09:34:54 +01:00
|
|
|
"realm_send_welcome_emails",
|
2017-10-20 16:55:04 +02:00
|
|
|
"realm_signup_notifications_stream_id",
|
2019-01-11 17:51:13 +01:00
|
|
|
"realm_upload_quota",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_uri",
|
2019-11-02 17:58:55 +01:00
|
|
|
"realm_user_group_edit_policy",
|
2017-11-07 07:56:26 +01:00
|
|
|
"realm_user_groups",
|
2017-04-24 21:59:07 +02:00
|
|
|
"realm_users",
|
2018-04-23 14:51:30 +02:00
|
|
|
"realm_video_chat_provider",
|
2017-03-08 11:57:55 +01:00
|
|
|
"realm_waiting_period_threshold",
|
2018-12-28 20:45:54 +01:00
|
|
|
"realm_zoom_api_key",
|
|
|
|
"realm_zoom_api_secret",
|
|
|
|
"realm_zoom_user_id",
|
2019-03-20 04:15:58 +01:00
|
|
|
"recent_private_conversations",
|
2017-08-28 23:01:18 +02:00
|
|
|
"root_domain_uri",
|
2017-03-08 11:57:55 +01:00
|
|
|
"save_stacktraces",
|
2018-07-14 11:32:08 +02:00
|
|
|
"search_pills_enabled",
|
2019-04-29 08:41:00 +02:00
|
|
|
"server_avatar_changes_disabled",
|
2017-03-08 11:57:55 +01:00
|
|
|
"server_generation",
|
2017-03-13 14:42:03 +01:00
|
|
|
"server_inline_image_preview",
|
|
|
|
"server_inline_url_embed_preview",
|
2019-05-03 08:09:03 +02:00
|
|
|
"server_name_changes_disabled",
|
2019-04-06 06:34:49 +02:00
|
|
|
"settings_send_digest_emails",
|
2018-08-17 08:09:07 +02:00
|
|
|
"starred_message_counts",
|
2018-08-14 23:57:20 +02:00
|
|
|
"starred_messages",
|
2019-01-27 18:57:15 +01:00
|
|
|
"stop_words",
|
2018-04-30 11:48:00 +02:00
|
|
|
"stream_description_max_length",
|
|
|
|
"stream_name_max_length",
|
2017-04-21 07:43:51 +02:00
|
|
|
"subscriptions",
|
2017-03-08 11:57:55 +01:00
|
|
|
"test_suite",
|
2017-03-14 10:53:09 +01:00
|
|
|
"timezone",
|
2018-01-15 19:36:32 +01:00
|
|
|
"translate_emoticons",
|
2018-05-03 11:08:50 +02:00
|
|
|
"translation_data",
|
2017-03-08 11:57:55 +01:00
|
|
|
"twenty_four_hour_time",
|
2017-07-17 07:17:21 +02:00
|
|
|
"two_fa_enabled",
|
|
|
|
"two_fa_enabled_user",
|
2017-05-23 03:02:01 +02:00
|
|
|
"unread_msgs",
|
2017-04-21 07:49:41 +02:00
|
|
|
"unsubscribed",
|
2019-06-12 08:56:28 +02:00
|
|
|
"upgrade_text_for_wide_organization_logo",
|
2017-03-08 11:57:55 +01:00
|
|
|
"user_id",
|
2019-01-21 19:06:03 +01:00
|
|
|
"user_status",
|
2018-01-26 22:09:38 +01:00
|
|
|
"warn_no_email",
|
2020-04-04 01:47:18 +02:00
|
|
|
"webpack_public_path",
|
2019-09-03 23:27:45 +02:00
|
|
|
"wildcard_mentions_notify",
|
2020-04-20 00:57:28 +02:00
|
|
|
"zulip_feature_level",
|
2017-03-08 11:57:55 +01:00
|
|
|
"zulip_version",
|
|
|
|
]
|
|
|
|
|
|
|
|
# Verify fails if logged-out
|
|
|
|
result = self.client_get('/')
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2017-04-21 08:24:30 +02:00
|
|
|
# Create bot for realm_bots testing. Must be done before fetching home_page.
|
2017-03-08 11:57:55 +01:00
|
|
|
bot_info = {
|
|
|
|
'full_name': 'The Bot of Hamlet',
|
|
|
|
'short_name': 'hambot',
|
|
|
|
}
|
|
|
|
self.client_post("/json/bots", bot_info)
|
|
|
|
|
|
|
|
# Verify succeeds once logged-in
|
2017-09-19 17:44:16 +02:00
|
|
|
flush_per_request_caches()
|
|
|
|
with queries_captured() as queries:
|
2017-10-21 21:50:07 +02:00
|
|
|
with patch('zerver.lib.cache.cache_set') as cache_mock:
|
|
|
|
result = self._get_home_page(stream='Denmark')
|
2019-10-02 00:10:30 +02:00
|
|
|
self.assertEqual(set(result["Cache-Control"].split(", ")),
|
|
|
|
{"must-revalidate", "no-store", "no-cache"})
|
2017-09-19 17:44:16 +02:00
|
|
|
|
2020-04-15 12:34:26 +02:00
|
|
|
self.assert_length(queries, 43)
|
2019-12-05 23:26:24 +01:00
|
|
|
self.assert_length(cache_mock.call_args_list, 5)
|
2017-09-19 17:44:16 +02:00
|
|
|
|
2017-03-08 11:57:55 +01:00
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
|
|
|
|
for html_bit in html_bits:
|
|
|
|
if html_bit not in html:
|
|
|
|
raise AssertionError('%s not in result' % (html_bit,))
|
|
|
|
|
|
|
|
page_params = self._get_page_params(result)
|
|
|
|
|
|
|
|
actual_keys = sorted([str(k) for k in page_params.keys()])
|
|
|
|
|
|
|
|
self.assertEqual(actual_keys, expected_keys)
|
|
|
|
|
|
|
|
# TODO: Inspect the page_params data further.
|
|
|
|
# print(ujson.dumps(page_params, indent=2))
|
2017-04-21 08:24:30 +02:00
|
|
|
realm_bots_expected_keys = [
|
2017-03-08 11:57:55 +01:00
|
|
|
'api_key',
|
|
|
|
'avatar_url',
|
2017-06-12 19:50:03 +02:00
|
|
|
'bot_type',
|
2017-03-08 11:57:55 +01:00
|
|
|
'default_all_public_streams',
|
|
|
|
'default_events_register_stream',
|
|
|
|
'default_sending_stream',
|
|
|
|
'email',
|
|
|
|
'full_name',
|
|
|
|
'is_active',
|
|
|
|
'owner',
|
2018-01-16 20:34:12 +01:00
|
|
|
'services',
|
2017-03-08 11:57:55 +01:00
|
|
|
'user_id',
|
|
|
|
]
|
|
|
|
|
2017-04-21 08:24:30 +02:00
|
|
|
realm_bots_actual_keys = sorted([str(key) for key in page_params['realm_bots'][0].keys()])
|
|
|
|
self.assertEqual(realm_bots_actual_keys, realm_bots_expected_keys)
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2017-07-13 13:42:57 +02:00
|
|
|
def test_home_under_2fa_without_otp_device(self) -> None:
|
|
|
|
with self.settings(TWO_FACTOR_AUTHENTICATION_ENABLED=True):
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('iago')
|
2017-07-13 13:42:57 +02:00
|
|
|
result = self._get_home_page()
|
|
|
|
# Should be successful because otp device is not configured.
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
|
|
|
def test_home_under_2fa_with_otp_device(self) -> None:
|
|
|
|
with self.settings(TWO_FACTOR_AUTHENTICATION_ENABLED=True):
|
|
|
|
user_profile = self.example_user('iago')
|
|
|
|
self.create_default_device(user_profile)
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-07-13 13:42:57 +02:00
|
|
|
result = self._get_home_page()
|
|
|
|
# User should not log in because otp device is configured but
|
|
|
|
# 2fa login function was not called.
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
|
|
|
|
self.login_2fa(user_profile)
|
|
|
|
result = self._get_home_page()
|
|
|
|
# Should be successful after calling 2fa login function.
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
2018-03-27 20:53:34 +02:00
|
|
|
def test_num_queries_for_realm_admin(self) -> None:
|
|
|
|
# Verify number of queries for Realm admin isn't much higher than for normal users.
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('iago')
|
2018-03-27 20:53:34 +02:00
|
|
|
flush_per_request_caches()
|
|
|
|
with queries_captured() as queries:
|
|
|
|
with patch('zerver.lib.cache.cache_set') as cache_mock:
|
|
|
|
result = self._get_home_page()
|
|
|
|
self.assertEqual(result.status_code, 200)
|
2019-03-20 13:13:44 +01:00
|
|
|
self.assert_length(cache_mock.call_args_list, 6)
|
2020-04-15 12:34:26 +02:00
|
|
|
self.assert_length(queries, 41)
|
2018-03-27 20:53:34 +02:00
|
|
|
|
2017-10-28 00:57:15 +02:00
|
|
|
@slow("Creates and subscribes 10 users in a loop. Should use bulk queries.")
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_num_queries_with_streams(self) -> None:
|
2017-09-19 23:34:07 +02:00
|
|
|
main_user = self.example_user('hamlet')
|
|
|
|
other_user = self.example_user('cordelia')
|
|
|
|
|
|
|
|
realm_id = main_user.realm_id
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(main_user)
|
2017-09-19 23:34:07 +02:00
|
|
|
|
|
|
|
# Try to make page-load do extra work for various subscribed
|
|
|
|
# streams.
|
|
|
|
for i in range(10):
|
|
|
|
stream_name = 'test_stream_' + str(i)
|
|
|
|
stream = self.make_stream(stream_name)
|
|
|
|
DefaultStream.objects.create(
|
|
|
|
realm_id=realm_id,
|
|
|
|
stream_id=stream.id
|
|
|
|
)
|
|
|
|
for user in [main_user, other_user]:
|
|
|
|
self.subscribe(user, stream_name)
|
|
|
|
|
|
|
|
# Simulate hitting the page the first time to avoid some noise
|
|
|
|
# related to initial logins.
|
|
|
|
self._get_home_page()
|
|
|
|
|
|
|
|
# Then for the second page load, measure the number of queries.
|
|
|
|
flush_per_request_caches()
|
|
|
|
with queries_captured() as queries2:
|
|
|
|
result = self._get_home_page()
|
|
|
|
|
2020-04-15 12:34:26 +02:00
|
|
|
self.assert_length(queries2, 38)
|
2017-09-19 23:34:07 +02:00
|
|
|
|
|
|
|
# Do a sanity check that our new streams were in the payload.
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('test_stream_7', html)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def _get_home_page(self, **kwargs: Any) -> HttpResponse:
|
2017-03-08 11:57:55 +01:00
|
|
|
with \
|
|
|
|
patch('zerver.lib.events.request_event_queue', return_value=42), \
|
|
|
|
patch('zerver.lib.events.get_user_events', return_value=[]):
|
|
|
|
result = self.client_get('/', dict(**kwargs))
|
|
|
|
return result
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def _get_page_params(self, result: HttpResponse) -> Dict[str, Any]:
|
2019-09-13 01:15:53 +02:00
|
|
|
doc = lxml.html.document_fromstring(result.content)
|
2019-09-19 02:47:12 +02:00
|
|
|
[div] = doc.xpath("//div[@id='page-params']")
|
|
|
|
page_params_json = div.get("data-params")
|
2017-03-08 11:57:55 +01:00
|
|
|
page_params = ujson.loads(page_params_json)
|
|
|
|
return page_params
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def _sanity_check(self, result: HttpResponse) -> None:
|
2017-03-08 11:57:55 +01:00
|
|
|
'''
|
|
|
|
Use this for tests that are geared toward specific edge cases, but
|
|
|
|
which still want the home page to load properly.
|
|
|
|
'''
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
if 'Compose your message' not in html:
|
|
|
|
raise AssertionError('Home page probably did not load.')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_terms_of_service(self) -> None:
|
2017-05-07 19:39:30 +02:00
|
|
|
user = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user)
|
2017-03-08 11:57:55 +01:00
|
|
|
|
|
|
|
for user_tos_version in [None, '1.1', '2.0.3.4']:
|
|
|
|
user.tos_version = user_tos_version
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
with \
|
|
|
|
self.settings(TERMS_OF_SERVICE='whatever'), \
|
|
|
|
self.settings(TOS_VERSION='99.99'):
|
|
|
|
|
|
|
|
result = self.client_get('/', dict(stream='Denmark'))
|
|
|
|
|
|
|
|
html = result.content.decode('utf-8')
|
2018-12-17 07:50:38 +01:00
|
|
|
self.assertIn('Accept the new Terms of Service', html)
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2020-03-25 02:00:28 +01:00
|
|
|
def test_banned_desktop_app_versions(self) -> None:
|
|
|
|
user = self.example_user('hamlet')
|
|
|
|
self.login_user(user)
|
|
|
|
|
|
|
|
result = self.client_get('/',
|
|
|
|
HTTP_USER_AGENT="ZulipElectron/2.3.82")
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('You are using old version of the Zulip desktop', html)
|
|
|
|
|
2020-04-20 14:00:03 +02:00
|
|
|
def test_unsupported_browser(self) -> None:
|
|
|
|
user = self.example_user('hamlet')
|
|
|
|
self.login_user(user)
|
|
|
|
|
|
|
|
# currently we don't support IE, so some of IE's user agents are added.
|
|
|
|
unsupported_user_agents = [
|
|
|
|
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2)",
|
|
|
|
"Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko",
|
|
|
|
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)"
|
|
|
|
]
|
|
|
|
for user_agent in unsupported_user_agents:
|
|
|
|
result = self.client_get('/',
|
|
|
|
HTTP_USER_AGENT=user_agent)
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('Internet Explorer is not supported by Zulip.', html)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_terms_of_service_first_time_template(self) -> None:
|
2017-05-07 19:39:30 +02:00
|
|
|
user = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user)
|
2017-03-25 21:23:54 +01:00
|
|
|
|
|
|
|
user.tos_version = None
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
with \
|
|
|
|
self.settings(FIRST_TIME_TOS_TEMPLATE='hello.html'), \
|
|
|
|
self.settings(TOS_VERSION='99.99'):
|
|
|
|
result = self.client_post('/accounts/accept_terms/')
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assert_in_response("I agree to the", result)
|
2020-03-17 22:41:05 +01:00
|
|
|
self.assert_in_response("Chat for distributed teams", result)
|
2017-03-25 21:23:54 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_accept_terms_of_service(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-25 21:23:54 +01:00
|
|
|
|
|
|
|
result = self.client_post('/accounts/accept_terms/')
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assert_in_response("I agree to the", result)
|
|
|
|
|
|
|
|
result = self.client_post('/accounts/accept_terms/', {'terms': True})
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
self.assertEqual(result['Location'], '/')
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_bad_narrow(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2019-03-09 02:36:01 +01:00
|
|
|
with patch('logging.warning') as mock:
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self._get_home_page(stream='Invalid Stream')
|
2018-05-21 04:06:14 +02:00
|
|
|
mock.assert_called_once()
|
2019-03-09 02:36:01 +01:00
|
|
|
self.assertEqual(mock.call_args_list[0][0][0], "Invalid narrow requested, ignoring")
|
2017-03-08 11:57:55 +01:00
|
|
|
self._sanity_check(result)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_bad_pointer(self) -> None:
|
2017-05-07 19:39:30 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
user_profile.pointer = 999999
|
|
|
|
user_profile.save()
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2020-04-28 07:29:08 +02:00
|
|
|
with patch('logging.warning') as mock:
|
|
|
|
result = self._get_home_page()
|
2020-05-02 08:44:14 +02:00
|
|
|
mock.assert_called_once_with(
|
|
|
|
'User %s has invalid pointer %s', user_profile.id, 999999,
|
|
|
|
)
|
2017-03-08 11:57:55 +01:00
|
|
|
self._sanity_check(result)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_topic_narrow(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self._get_home_page(stream='Denmark', topic='lunch')
|
|
|
|
self._sanity_check(result)
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('lunch', html)
|
2019-10-02 00:10:30 +02:00
|
|
|
self.assertEqual(set(result["Cache-Control"].split(", ")),
|
|
|
|
{"must-revalidate", "no-store", "no-cache"})
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_notifications_stream(self) -> None:
|
2017-03-08 11:57:55 +01:00
|
|
|
realm = get_realm('zulip')
|
2017-09-17 19:53:38 +02:00
|
|
|
realm.notifications_stream_id = get_stream('Denmark', realm).id
|
2017-03-08 11:57:55 +01:00
|
|
|
realm.save()
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self._get_home_page()
|
|
|
|
page_params = self._get_page_params(result)
|
2017-05-17 03:48:47 +02:00
|
|
|
self.assertEqual(page_params['realm_notifications_stream_id'], get_stream('Denmark', realm).id)
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2018-05-11 01:39:38 +02:00
|
|
|
def create_bot(self, owner: UserProfile, bot_email: str, bot_name: str) -> UserProfile:
|
2017-10-21 19:42:11 +02:00
|
|
|
user = do_create_user(
|
|
|
|
email=bot_email,
|
|
|
|
password='123',
|
|
|
|
realm=owner.realm,
|
|
|
|
full_name=bot_name,
|
|
|
|
short_name=bot_name,
|
|
|
|
bot_type=UserProfile.DEFAULT_BOT,
|
|
|
|
bot_owner=owner
|
|
|
|
)
|
|
|
|
return user
|
|
|
|
|
2018-05-11 01:39:38 +02:00
|
|
|
def create_non_active_user(self, realm: Realm, email: str, name: str) -> UserProfile:
|
2017-10-21 19:42:11 +02:00
|
|
|
user = do_create_user(
|
|
|
|
email=email,
|
|
|
|
password='123',
|
|
|
|
realm=realm,
|
|
|
|
full_name=name,
|
|
|
|
short_name=name,
|
|
|
|
)
|
2017-10-28 19:22:02 +02:00
|
|
|
|
|
|
|
# Doing a full-stack deactivation would be expensive here,
|
|
|
|
# and we really only need to flip the flag to get a valid
|
|
|
|
# test.
|
|
|
|
user.is_active = False
|
|
|
|
user.save()
|
2017-10-21 19:42:11 +02:00
|
|
|
return user
|
|
|
|
|
2017-12-20 21:03:51 +01:00
|
|
|
def test_signup_notifications_stream(self) -> None:
|
2017-10-20 16:55:04 +02:00
|
|
|
realm = get_realm('zulip')
|
|
|
|
realm.signup_notifications_stream = get_stream('Denmark', realm)
|
|
|
|
realm.save()
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-10-20 16:55:04 +02:00
|
|
|
result = self._get_home_page()
|
|
|
|
page_params = self._get_page_params(result)
|
|
|
|
self.assertEqual(page_params['realm_signup_notifications_stream_id'], get_stream('Denmark', realm).id)
|
|
|
|
|
2017-10-21 19:42:11 +02:00
|
|
|
@slow('creating users and loading home page')
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_people(self) -> None:
|
2017-10-21 19:42:11 +02:00
|
|
|
hamlet = self.example_user('hamlet')
|
2017-05-23 20:57:59 +02:00
|
|
|
realm = get_realm('zulip')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(hamlet)
|
2017-10-21 19:42:11 +02:00
|
|
|
|
2020-03-12 14:17:25 +01:00
|
|
|
bots = {}
|
2017-10-21 19:42:11 +02:00
|
|
|
for i in range(3):
|
2020-03-12 14:17:25 +01:00
|
|
|
bots[i] = self.create_bot(
|
2017-10-21 19:42:11 +02:00
|
|
|
owner=hamlet,
|
|
|
|
bot_email='bot-%d@zulip.com' % (i,),
|
|
|
|
bot_name='Bot %d' % (i,),
|
|
|
|
)
|
|
|
|
|
|
|
|
for i in range(3):
|
2020-03-12 14:17:25 +01:00
|
|
|
defunct_user = self.create_non_active_user(
|
2017-10-21 19:42:11 +02:00
|
|
|
realm=realm,
|
|
|
|
email='defunct-%d@zulip.com' % (i,),
|
|
|
|
name='Defunct User %d' % (i,),
|
|
|
|
)
|
|
|
|
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self._get_home_page()
|
|
|
|
page_params = self._get_page_params(result)
|
2017-10-21 19:42:11 +02:00
|
|
|
|
|
|
|
'''
|
|
|
|
We send three lists of users. The first two below are disjoint
|
|
|
|
lists of users, and the records we send for them have identical
|
|
|
|
structure.
|
|
|
|
|
|
|
|
The realm_bots bucket is somewhat redundant, since all bots will
|
|
|
|
be in one of the first two buckets. They do include fields, however,
|
|
|
|
that normal users don't care about, such as default_sending_stream.
|
|
|
|
'''
|
|
|
|
|
|
|
|
buckets = [
|
|
|
|
'realm_users',
|
|
|
|
'realm_non_active_users',
|
|
|
|
'realm_bots',
|
|
|
|
]
|
|
|
|
|
|
|
|
for field in buckets:
|
|
|
|
users = page_params[field]
|
|
|
|
self.assertTrue(len(users) >= 3, field)
|
|
|
|
for rec in users:
|
|
|
|
self.assertEqual(rec['user_id'],
|
|
|
|
get_user(rec['email'], realm).id)
|
|
|
|
if field == 'realm_bots':
|
|
|
|
self.assertNotIn('is_bot', rec)
|
|
|
|
self.assertIn('is_active', rec)
|
|
|
|
self.assertIn('owner', rec)
|
|
|
|
else:
|
|
|
|
self.assertIn('is_bot', rec)
|
|
|
|
self.assertNotIn('is_active', rec)
|
|
|
|
|
2020-03-12 14:17:25 +01:00
|
|
|
active_ids = {p['user_id'] for p in page_params['realm_users']}
|
|
|
|
non_active_ids = {p['user_id'] for p in page_params['realm_non_active_users']}
|
|
|
|
bot_ids = {p['user_id'] for p in page_params['realm_bots']}
|
2017-10-21 19:42:11 +02:00
|
|
|
|
2020-03-12 14:17:25 +01:00
|
|
|
self.assertIn(hamlet.id, active_ids)
|
|
|
|
self.assertIn(defunct_user.id, non_active_ids)
|
2017-10-21 19:42:11 +02:00
|
|
|
|
|
|
|
# Bots can show up in multiple buckets.
|
2020-03-12 14:17:25 +01:00
|
|
|
self.assertIn(bots[2].id, bot_ids)
|
|
|
|
self.assertIn(bots[2].id, active_ids)
|
2017-10-21 19:42:11 +02:00
|
|
|
|
|
|
|
# Make sure nobody got mis-bucketed.
|
2020-03-12 14:17:25 +01:00
|
|
|
self.assertNotIn(hamlet.id, non_active_ids)
|
|
|
|
self.assertNotIn(defunct_user.id, active_ids)
|
2017-03-08 11:57:55 +01:00
|
|
|
|
|
|
|
cross_bots = page_params['cross_realm_bots']
|
2020-01-18 08:56:19 +01:00
|
|
|
self.assertEqual(len(cross_bots), 3)
|
2017-03-08 11:57:55 +01:00
|
|
|
cross_bots.sort(key=lambda d: d['email'])
|
2018-08-02 00:06:38 +02:00
|
|
|
for cross_bot in cross_bots:
|
|
|
|
# These are either nondeterministic or boring
|
|
|
|
del cross_bot['timezone']
|
|
|
|
del cross_bot['avatar_url']
|
|
|
|
del cross_bot['date_joined']
|
2017-05-08 17:42:50 +02:00
|
|
|
|
|
|
|
notification_bot = self.notification_bot()
|
2020-01-14 18:19:35 +01:00
|
|
|
email_gateway_bot = get_system_bot(settings.EMAIL_GATEWAY_BOT)
|
|
|
|
welcome_bot = get_system_bot(settings.WELCOME_BOT)
|
2017-05-08 17:42:50 +02:00
|
|
|
|
2017-11-10 23:36:13 +01:00
|
|
|
by_email = lambda d: d['email']
|
|
|
|
|
|
|
|
self.assertEqual(sorted(cross_bots, key=by_email), sorted([
|
|
|
|
dict(
|
2020-01-07 13:58:58 +01:00
|
|
|
bot_owner_id=None,
|
2020-01-14 18:19:35 +01:00
|
|
|
bot_type=1,
|
|
|
|
email=email_gateway_bot.email,
|
|
|
|
user_id=email_gateway_bot.id,
|
|
|
|
full_name=email_gateway_bot.full_name,
|
|
|
|
is_active=True,
|
|
|
|
is_bot=True,
|
|
|
|
is_admin=False,
|
|
|
|
is_cross_realm_bot=True,
|
|
|
|
is_guest=False
|
2017-11-10 23:36:13 +01:00
|
|
|
),
|
2017-03-08 11:57:55 +01:00
|
|
|
dict(
|
2020-01-14 18:19:35 +01:00
|
|
|
bot_owner_id=None,
|
|
|
|
bot_type=1,
|
|
|
|
email=notification_bot.email,
|
2017-05-08 17:42:50 +02:00
|
|
|
user_id=notification_bot.id,
|
2020-01-14 18:19:35 +01:00
|
|
|
full_name=notification_bot.full_name,
|
|
|
|
is_active=True,
|
|
|
|
is_bot=True,
|
2017-03-08 11:57:55 +01:00
|
|
|
is_admin=False,
|
2020-01-14 18:19:35 +01:00
|
|
|
is_cross_realm_bot=True,
|
|
|
|
is_guest=False
|
2017-03-08 11:57:55 +01:00
|
|
|
),
|
2017-06-11 18:34:25 +02:00
|
|
|
dict(
|
2020-01-07 13:58:58 +01:00
|
|
|
bot_owner_id=None,
|
2020-01-14 18:19:35 +01:00
|
|
|
bot_type=1,
|
|
|
|
email=welcome_bot.email,
|
|
|
|
user_id=welcome_bot.id,
|
|
|
|
full_name=welcome_bot.full_name,
|
|
|
|
is_active=True,
|
|
|
|
is_bot=True,
|
|
|
|
is_admin=False,
|
|
|
|
is_cross_realm_bot=True,
|
|
|
|
is_guest=False
|
2017-06-11 18:34:25 +02:00
|
|
|
),
|
2017-11-10 23:36:13 +01:00
|
|
|
], key=by_email))
|
2017-03-08 11:57:55 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_new_stream(self) -> None:
|
2017-08-25 06:01:29 +02:00
|
|
|
user_profile = self.example_user("hamlet")
|
2017-03-08 11:57:55 +01:00
|
|
|
stream_name = 'New stream'
|
2017-08-25 06:01:29 +02:00
|
|
|
self.subscribe(user_profile, stream_name)
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self._get_home_page(stream=stream_name)
|
|
|
|
page_params = self._get_page_params(result)
|
|
|
|
self.assertEqual(page_params['narrow_stream'], stream_name)
|
|
|
|
self.assertEqual(page_params['narrow'], [dict(operator='stream', operand=stream_name)])
|
2017-04-24 21:33:48 +02:00
|
|
|
self.assertEqual(page_params['pointer'], -1)
|
2017-03-08 11:57:55 +01:00
|
|
|
self.assertEqual(page_params['max_message_id'], -1)
|
|
|
|
self.assertEqual(page_params['have_initial_messages'], False)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_invites_by_admins_only(self) -> None:
|
2017-05-07 19:39:30 +02:00
|
|
|
user_profile = self.example_user('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
|
|
|
|
realm = user_profile.realm
|
|
|
|
realm.invite_by_admins_only = True
|
|
|
|
realm.save()
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2017-03-08 11:57:55 +01:00
|
|
|
self.assertFalse(user_profile.is_realm_admin)
|
|
|
|
result = self._get_home_page()
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertNotIn('Invite more users', html)
|
|
|
|
|
2019-10-05 02:35:07 +02:00
|
|
|
user_profile.role = UserProfile.ROLE_REALM_ADMINISTRATOR
|
2017-03-08 11:57:55 +01:00
|
|
|
user_profile.save()
|
|
|
|
result = self._get_home_page()
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('Invite more users', html)
|
|
|
|
|
2018-06-08 14:43:27 +02:00
|
|
|
def test_show_invites_for_guest_users(self) -> None:
|
|
|
|
user_profile = self.example_user('polonius')
|
|
|
|
|
|
|
|
realm = user_profile.realm
|
|
|
|
realm.invite_by_admins_only = False
|
|
|
|
realm.save()
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user_profile)
|
2018-06-08 14:43:27 +02:00
|
|
|
self.assertFalse(user_profile.is_realm_admin)
|
|
|
|
self.assertFalse(get_realm('zulip').invite_by_admins_only)
|
|
|
|
result = self._get_home_page()
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertNotIn('Invite more users', html)
|
|
|
|
|
2018-08-15 18:49:25 +02:00
|
|
|
def test_show_billing(self) -> None:
|
|
|
|
customer = Customer.objects.create(realm=get_realm("zulip"), stripe_customer_id="cus_id")
|
|
|
|
|
2019-01-31 22:58:28 +01:00
|
|
|
# realm admin, but no CustomerPlan -> no billing link
|
2018-08-15 18:49:25 +02:00
|
|
|
user = self.example_user('iago')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user)
|
2018-08-15 18:49:25 +02:00
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertNotIn('Billing', result_html)
|
|
|
|
|
2019-01-31 22:58:28 +01:00
|
|
|
# realm admin, with inactive CustomerPlan -> show billing link
|
2019-01-31 23:18:53 +01:00
|
|
|
CustomerPlan.objects.create(customer=customer, billing_cycle_anchor=timezone_now(),
|
2019-01-31 22:58:28 +01:00
|
|
|
billing_schedule=CustomerPlan.ANNUAL, next_invoice_date=timezone_now(),
|
|
|
|
tier=CustomerPlan.STANDARD, status=CustomerPlan.ENDED)
|
2018-08-15 18:49:25 +02:00
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertIn('Billing', result_html)
|
|
|
|
|
2019-01-31 22:58:28 +01:00
|
|
|
# billing admin, with CustomerPlan -> show billing link
|
2019-10-05 02:35:07 +02:00
|
|
|
user.role = UserProfile.ROLE_REALM_ADMINISTRATOR
|
2018-08-15 18:49:25 +02:00
|
|
|
user.is_billing_admin = True
|
2019-10-05 02:35:07 +02:00
|
|
|
user.save(update_fields=['role', 'is_billing_admin'])
|
2018-08-15 18:49:25 +02:00
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertIn('Billing', result_html)
|
|
|
|
|
2019-01-31 22:58:28 +01:00
|
|
|
# billing admin, but no CustomerPlan -> no billing link
|
|
|
|
CustomerPlan.objects.all().delete()
|
2018-08-15 18:49:25 +02:00
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertNotIn('Billing', result_html)
|
|
|
|
|
|
|
|
# billing admin, no customer object -> make sure it doesn't crash
|
|
|
|
customer.delete()
|
|
|
|
result = self._get_home_page()
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
|
|
|
def test_show_plans(self) -> None:
|
|
|
|
realm = get_realm("zulip")
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2018-08-15 18:49:25 +02:00
|
|
|
|
|
|
|
# Show plans link to all users if plan_type is LIMITED
|
|
|
|
realm.plan_type = Realm.LIMITED
|
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertIn('Plans', result_html)
|
|
|
|
|
2018-10-24 06:09:01 +02:00
|
|
|
# Show plans link to no one, including admins, if SELF_HOSTED or STANDARD
|
2018-08-15 18:49:25 +02:00
|
|
|
realm.plan_type = Realm.SELF_HOSTED
|
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertNotIn('Plans', result_html)
|
|
|
|
|
2018-10-24 06:09:01 +02:00
|
|
|
realm.plan_type = Realm.STANDARD
|
2018-08-15 18:49:25 +02:00
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result_html = self._get_home_page().content.decode('utf-8')
|
|
|
|
self.assertNotIn('Plans', result_html)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_desktop_home(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self.client_get("/desktop_home")
|
|
|
|
self.assertEqual(result.status_code, 301)
|
|
|
|
self.assertTrue(result["Location"].endswith("/desktop_home/"))
|
|
|
|
result = self.client_get("/desktop_home/")
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
path = urllib.parse.urlparse(result['Location']).path
|
|
|
|
self.assertEqual(path, "/")
|
|
|
|
|
2019-03-02 18:23:57 +01:00
|
|
|
def test_compute_navbar_logo_url(self) -> None:
|
|
|
|
user_profile = self.example_user("hamlet")
|
|
|
|
|
|
|
|
page_params = {"night_mode": True}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
|
|
|
"/static/images/logo/zulip-org-logo.png?version=0")
|
|
|
|
|
|
|
|
page_params = {"night_mode": False}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
|
|
|
"/static/images/logo/zulip-org-logo.png?version=0")
|
|
|
|
|
|
|
|
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=False)
|
|
|
|
page_params = {"night_mode": True}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
2019-07-15 21:54:11 +02:00
|
|
|
"/user_avatars/%s/realm/logo.png?version=2" % (user_profile.realm_id,))
|
2019-03-02 18:23:57 +01:00
|
|
|
|
|
|
|
page_params = {"night_mode": False}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
2019-07-15 21:54:11 +02:00
|
|
|
"/user_avatars/%s/realm/logo.png?version=2" % (user_profile.realm_id,))
|
2019-03-02 18:23:57 +01:00
|
|
|
|
|
|
|
do_change_logo_source(user_profile.realm, Realm.LOGO_UPLOADED, night=True)
|
|
|
|
page_params = {"night_mode": True}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
2019-07-15 21:54:11 +02:00
|
|
|
"/user_avatars/%s/realm/night_logo.png?version=2" % (user_profile.realm_id,))
|
2019-03-02 18:23:57 +01:00
|
|
|
|
|
|
|
page_params = {"night_mode": False}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
2019-07-15 21:54:11 +02:00
|
|
|
"/user_avatars/%s/realm/logo.png?version=2" % (user_profile.realm_id,))
|
2019-03-02 18:23:57 +01:00
|
|
|
|
|
|
|
# This configuration isn't super supported in the UI and is a
|
|
|
|
# weird choice, but we have a test for it anyway.
|
|
|
|
do_change_logo_source(user_profile.realm, Realm.LOGO_DEFAULT, night=False)
|
|
|
|
page_params = {"night_mode": True}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
2019-07-15 21:54:11 +02:00
|
|
|
"/user_avatars/%s/realm/night_logo.png?version=2" % (user_profile.realm_id,))
|
2019-03-02 18:23:57 +01:00
|
|
|
|
|
|
|
page_params = {"night_mode": False}
|
|
|
|
add_realm_logo_fields(page_params, user_profile.realm)
|
|
|
|
self.assertEqual(compute_navbar_logo_url(page_params),
|
|
|
|
"/static/images/logo/zulip-org-logo.png?version=0")
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_generate_204(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-03-08 11:57:55 +01:00
|
|
|
result = self.client_get("/api/v1/generate_204")
|
|
|
|
self.assertEqual(result.status_code, 204)
|
2017-03-25 21:23:54 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_message_sent_time(self) -> None:
|
2017-03-25 21:23:54 +01:00
|
|
|
epoch_seconds = 1490472096
|
2019-08-28 02:43:19 +02:00
|
|
|
date_sent = datetime.datetime.fromtimestamp(epoch_seconds)
|
2017-03-25 21:23:54 +01:00
|
|
|
user_message = MagicMock()
|
2019-08-28 02:43:19 +02:00
|
|
|
user_message.message.date_sent = date_sent
|
2017-03-25 21:23:54 +01:00
|
|
|
self.assertEqual(sent_time_in_epoch_seconds(user_message), epoch_seconds)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_subdomain_homepage(self) -> None:
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('hamlet')
|
2017-08-25 04:32:16 +02:00
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
2017-03-25 21:23:54 +01:00
|
|
|
with patch('zerver.views.home.get_subdomain', return_value=""):
|
|
|
|
result = self._get_home_page()
|
|
|
|
self.assertEqual(result.status_code, 200)
|
2020-03-17 22:41:05 +01:00
|
|
|
self.assert_in_response('Chat for distributed teams', result)
|
2017-03-25 21:23:54 +01:00
|
|
|
|
|
|
|
with patch('zerver.views.home.get_subdomain', return_value="subdomain"):
|
|
|
|
result = self._get_home_page()
|
|
|
|
self._sanity_check(result)
|
2017-07-16 09:41:38 +02:00
|
|
|
|
2017-11-19 04:02:03 +01:00
|
|
|
def send_test_message(self, content: str, sender_name: str='iago',
|
|
|
|
stream_name: str='Denmark', topic_name: str='foo') -> None:
|
2020-03-07 11:43:05 +01:00
|
|
|
sender = self.example_user(sender_name)
|
2017-10-28 17:04:30 +02:00
|
|
|
self.send_stream_message(sender, stream_name,
|
|
|
|
content=content, topic_name=topic_name)
|
2017-07-16 09:41:38 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def soft_activate_and_get_unread_count(self, stream: str='Denmark', topic: str='foo') -> int:
|
2017-07-16 09:41:38 +02:00
|
|
|
stream_narrow = self._get_home_page(stream=stream, topic=topic)
|
|
|
|
page_params = self._get_page_params(stream_narrow)
|
|
|
|
return page_params['unread_msgs']['count']
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_unread_count_user_soft_deactivation(self) -> None:
|
2017-07-16 09:41:38 +02:00
|
|
|
# In this test we make sure if a soft deactivated user had unread
|
|
|
|
# messages before deactivation they remain same way after activation.
|
|
|
|
long_term_idle_user = self.example_user('hamlet')
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(long_term_idle_user)
|
2017-07-16 09:41:38 +02:00
|
|
|
message = 'Test Message 1'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2017-07-16 09:41:38 +02:00
|
|
|
with queries_captured() as queries:
|
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 1)
|
|
|
|
query_count = len(queries)
|
|
|
|
user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(user_msg_list[-1].content, message)
|
|
|
|
self.logout()
|
|
|
|
|
|
|
|
do_soft_deactivate_users([long_term_idle_user])
|
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(long_term_idle_user)
|
2017-07-16 09:41:38 +02:00
|
|
|
message = 'Test Message 2'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2017-07-16 09:41:38 +02:00
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertNotEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
with queries_captured() as queries:
|
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 2)
|
|
|
|
# Test here for query count to be at least 5 greater than previous count
|
|
|
|
# This will assure indirectly that add_missing_messages() was called.
|
|
|
|
self.assertGreaterEqual(len(queries) - query_count, 5)
|
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
|
2017-10-28 00:57:15 +02:00
|
|
|
@slow("Loads home page data several times testing different cases")
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_multiple_user_soft_deactivations(self) -> None:
|
2017-07-16 09:41:38 +02:00
|
|
|
long_term_idle_user = self.example_user('hamlet')
|
2017-08-18 10:09:54 +02:00
|
|
|
# We are sending this message to ensure that long_term_idle_user has
|
|
|
|
# at least one UserMessage row.
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message('Testing', sender_name='hamlet')
|
2017-07-16 09:41:38 +02:00
|
|
|
do_soft_deactivate_users([long_term_idle_user])
|
|
|
|
|
|
|
|
message = 'Test Message 1'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(long_term_idle_user)
|
2017-07-16 09:41:38 +02:00
|
|
|
with queries_captured() as queries:
|
2017-08-18 10:09:54 +02:00
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 2)
|
2017-07-16 09:41:38 +02:00
|
|
|
query_count = len(queries)
|
|
|
|
long_term_idle_user.refresh_from_db()
|
|
|
|
self.assertFalse(long_term_idle_user.long_term_idle)
|
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
|
|
|
|
message = 'Test Message 2'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2017-07-16 09:41:38 +02:00
|
|
|
with queries_captured() as queries:
|
2017-08-18 10:09:54 +02:00
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 3)
|
2017-07-16 09:41:38 +02:00
|
|
|
# Test here for query count to be at least 5 less than previous count.
|
|
|
|
# This will assure add_missing_messages() isn't repeatedly called.
|
|
|
|
self.assertGreaterEqual(query_count - len(queries), 5)
|
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
self.logout()
|
|
|
|
|
|
|
|
do_soft_deactivate_users([long_term_idle_user])
|
|
|
|
|
|
|
|
message = 'Test Message 3'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(long_term_idle_user)
|
2017-07-16 09:41:38 +02:00
|
|
|
with queries_captured() as queries:
|
2017-08-18 10:09:54 +02:00
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 4)
|
2017-07-16 09:41:38 +02:00
|
|
|
query_count = len(queries)
|
|
|
|
long_term_idle_user.refresh_from_db()
|
|
|
|
self.assertFalse(long_term_idle_user.long_term_idle)
|
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
|
|
|
|
message = 'Test Message 4'
|
2017-10-27 17:57:23 +02:00
|
|
|
self.send_test_message(message)
|
2017-07-16 09:41:38 +02:00
|
|
|
with queries_captured() as queries:
|
2017-08-18 10:09:54 +02:00
|
|
|
self.assertEqual(self.soft_activate_and_get_unread_count(), 5)
|
2017-07-16 09:41:38 +02:00
|
|
|
self.assertGreaterEqual(query_count - len(queries), 5)
|
|
|
|
idle_user_msg_list = get_user_messages(long_term_idle_user)
|
|
|
|
self.assertEqual(idle_user_msg_list[-1].content, message)
|
|
|
|
self.logout()
|
2018-05-03 11:08:50 +02:00
|
|
|
|
2018-05-30 17:30:33 +02:00
|
|
|
def test_url_language(self) -> None:
|
|
|
|
user = self.example_user("hamlet")
|
|
|
|
user.default_language = 'es'
|
|
|
|
user.save()
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user)
|
2018-05-30 17:30:33 +02:00
|
|
|
result = self._get_home_page()
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
with \
|
|
|
|
patch('zerver.lib.events.request_event_queue', return_value=42), \
|
|
|
|
patch('zerver.lib.events.get_user_events', return_value=[]):
|
|
|
|
result = self.client_get('/de/')
|
|
|
|
page_params = self._get_page_params(result)
|
|
|
|
self.assertEqual(page_params['default_language'], 'es')
|
|
|
|
# TODO: Verify that the actual language we're using in the
|
|
|
|
# translation data is German.
|
|
|
|
|
2018-05-03 11:08:50 +02:00
|
|
|
def test_translation_data(self) -> None:
|
|
|
|
user = self.example_user("hamlet")
|
|
|
|
user.default_language = 'es'
|
|
|
|
user.save()
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login_user(user)
|
2018-05-03 11:08:50 +02:00
|
|
|
result = self._get_home_page()
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
2018-05-30 17:30:33 +02:00
|
|
|
page_params = self._get_page_params(result)
|
|
|
|
self.assertEqual(page_params['default_language'], 'es')
|
2018-08-14 13:50:02 +02:00
|
|
|
|
2020-01-13 18:47:30 +01:00
|
|
|
def test_compute_show_invites_and_add_streams_admin(self) -> None:
|
|
|
|
user = self.example_user("iago")
|
|
|
|
|
|
|
|
realm = user.realm
|
|
|
|
realm.invite_by_admins_only = True
|
|
|
|
realm.save()
|
|
|
|
|
|
|
|
show_invites, show_add_streams = compute_show_invites_and_add_streams(user)
|
|
|
|
self.assertEqual(show_invites, True)
|
|
|
|
self.assertEqual(show_add_streams, True)
|
|
|
|
|
|
|
|
def test_compute_show_invites_and_add_streams_require_admin(self) -> None:
|
|
|
|
user = self.example_user("hamlet")
|
|
|
|
|
|
|
|
realm = user.realm
|
|
|
|
realm.invite_by_admins_only = True
|
|
|
|
realm.save()
|
|
|
|
|
|
|
|
show_invites, show_add_streams = compute_show_invites_and_add_streams(user)
|
|
|
|
self.assertEqual(show_invites, False)
|
|
|
|
self.assertEqual(show_add_streams, True)
|
|
|
|
|
|
|
|
def test_compute_show_invites_and_add_streams_guest(self) -> None:
|
|
|
|
user = self.example_user("polonius")
|
|
|
|
|
|
|
|
show_invites, show_add_streams = compute_show_invites_and_add_streams(user)
|
|
|
|
self.assertEqual(show_invites, False)
|
|
|
|
self.assertEqual(show_add_streams, False)
|
2019-09-14 02:22:41 +02:00
|
|
|
|
|
|
|
def test_compute_show_invites_and_add_streams_unauthenticated(self) -> None:
|
|
|
|
show_invites, show_add_streams = compute_show_invites_and_add_streams(None)
|
|
|
|
self.assertEqual(show_invites, False)
|
|
|
|
self.assertEqual(show_add_streams, False)
|