def test_user_settings_based_on_client_capabilities(self) -> None: hamlet = self.example_user("hamlet") result = fetch_initial_state_data( user_profile=hamlet, user_settings_object=True, ) self.assertIn("user_settings", result) for prop in UserProfile.property_types: self.assertNotIn(prop, result) self.assertIn(prop, result["user_settings"]) for prop in UserProfile.notification_setting_types: self.assertNotIn(prop, result) self.assertIn(prop, result["user_settings"]) result = fetch_initial_state_data( user_profile=hamlet, user_settings_object=False, ) self.assertIn("user_settings", result) for prop in UserProfile.property_types: self.assertIn(prop, result) self.assertIn(prop, result["user_settings"]) for prop in UserProfile.notification_setting_types: self.assertIn(prop, result) self.assertIn(prop, result["user_settings"])
def test_delivery_email_presence_for_non_admins(self) -> None: user_profile = self.example_user("aaron") self.assertFalse(user_profile.is_realm_admin) do_set_realm_property( user_profile.realm, "email_address_visibility", Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE, acting_user=None, ) result = fetch_initial_state_data(user_profile) for key, value in result["raw_users"].items(): self.assertNotIn("delivery_email", value) do_set_realm_property( user_profile.realm, "email_address_visibility", Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS, acting_user=None, ) result = fetch_initial_state_data(user_profile) for key, value in result["raw_users"].items(): self.assertNotIn("delivery_email", value)
def test_queries(self) -> None: user = self.example_user("hamlet") self.login_user(user) flush_per_request_caches() with queries_captured() as queries: with mock.patch("zerver.lib.events.always_want") as want_mock: fetch_initial_state_data(user) self.assert_length(queries, 31) expected_counts = dict( alert_words=1, custom_profile_fields=1, default_streams=1, default_stream_groups=1, hotspots=0, message=1, muted_topics=1, muted_users=1, presence=1, realm=0, realm_bot=1, realm_domains=1, realm_embedded_bots=0, realm_incoming_webhook_bots=0, realm_emoji=1, realm_filters=1, realm_playgrounds=1, realm_user=3, realm_user_groups=2, recent_private_conversations=1, starred_messages=1, stream=2, stop_words=0, subscription=4, update_display_settings=0, update_global_notifications=0, update_message_flags=5, user_status=1, video_calls=0, giphy=0, ) wanted_event_types = {item[0][0] for item in want_mock.call_args_list} self.assertEqual(wanted_event_types, set(expected_counts)) for event_type in sorted(wanted_event_types): count = expected_counts[event_type] flush_per_request_caches() with queries_captured() as queries: if event_type == "update_message_flags": event_types = ["update_message_flags", "message"] else: event_types = [event_type] fetch_initial_state_data(user, event_types=event_types) self.assert_length(queries, count)
def test_delivery_email_presence_for_admins(self) -> None: user_profile = self.example_user('iago') self.assertTrue(user_profile.is_realm_admin) do_set_realm_property(user_profile.realm, "email_address_visibility", Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE) result = fetch_initial_state_data(user_profile, None, "", client_gravatar=False, user_avatar_url_field_optional=False, realm=user_profile.realm) for key, value in result['raw_users'].items(): self.assertNotIn('delivery_email', value) do_set_realm_property(user_profile.realm, "email_address_visibility", Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS) result = fetch_initial_state_data(user_profile, None, "", client_gravatar=False, user_avatar_url_field_optional=False, realm=user_profile.realm) for key, value in result['raw_users'].items(): self.assertIn('delivery_email', value)
def test_user_avatar_url_field_optional(self) -> None: hamlet = self.example_user('hamlet') users = [ self.example_user('iago'), self.example_user('cordelia'), self.example_user('ZOE'), self.example_user('othello'), ] for user in users: user.long_term_idle = True user.save() long_term_idle_users_ids = [user.id for user in users] result = fetch_initial_state_data(user_profile=hamlet, event_types=None, queue_id='', client_gravatar=False, user_avatar_url_field_optional=True, realm=hamlet.realm) raw_users = result['raw_users'] for user_dict in raw_users.values(): if user_dict['user_id'] in long_term_idle_users_ids: self.assertFalse('avatar_url' in user_dict) else: self.assertIsNotNone(user_dict['avatar_url']) gravatar_users_id = [ user_dict['user_id'] for user_dict in raw_users.values() if 'avatar_url' in user_dict and 'gravatar.com' in user_dict['avatar_url'] ] # Test again with client_gravatar = True result = fetch_initial_state_data(user_profile=hamlet, event_types=None, queue_id='', client_gravatar=True, user_avatar_url_field_optional=True, realm=hamlet.realm) raw_users = result['raw_users'] for user_dict in raw_users.values(): if user_dict['user_id'] in gravatar_users_id: self.assertIsNone(user_dict['avatar_url']) else: self.assertFalse('avatar_url' in user_dict)
def test_user_avatar_url_field_optional(self) -> None: hamlet = self.example_user("hamlet") users = [ self.example_user("iago"), self.example_user("cordelia"), self.example_user("ZOE"), self.example_user("othello"), ] for user in users: user.long_term_idle = True user.save() long_term_idle_users_ids = [user.id for user in users] result = fetch_initial_state_data( user_profile=hamlet, user_avatar_url_field_optional=True, ) raw_users = result["raw_users"] for user_dict in raw_users.values(): if user_dict["user_id"] in long_term_idle_users_ids: self.assertFalse("avatar_url" in user_dict) else: self.assertIsNotNone(user_dict["avatar_url"]) gravatar_users_id = [ user_dict["user_id"] for user_dict in raw_users.values() if "avatar_url" in user_dict and "gravatar.com" in user_dict["avatar_url"] ] # Test again with client_gravatar = True result = fetch_initial_state_data( user_profile=hamlet, client_gravatar=True, user_avatar_url_field_optional=True, ) raw_users = result["raw_users"] for user_dict in raw_users.values(): if user_dict["user_id"] in gravatar_users_id: self.assertIsNone(user_dict["avatar_url"]) else: self.assertFalse("avatar_url" in user_dict)
def test_realm_bots_admin(self) -> None: user_profile = self.example_user("hamlet") do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR, acting_user=None) self.assertTrue(user_profile.is_realm_admin) result = fetch_initial_state_data(user_profile) self.assertGreater(len(result["realm_bots"]), 2)
def test_realm_bots_non_admin(self) -> None: user_profile = self.example_user("cordelia") self.assertFalse(user_profile.is_realm_admin) result = fetch_initial_state_data(user_profile) self.assert_length(result["realm_bots"], 0) # additionally the API key for a random bot is not present in the data api_key = get_api_key(self.notification_bot(user_profile.realm)) self.assertNotIn(api_key, str(result))
def test_max_message_id_with_no_history(self) -> None: user_profile = self.example_user('aaron') # Delete all historical messages for this user UserMessage.objects.filter(user_profile=user_profile).delete() result = fetch_initial_state_data(user_profile, None, "", client_gravatar=False, user_avatar_url_field_optional=False) self.assertEqual(result['max_message_id'], -1)
def test_realm_bots_admin(self) -> None: user_profile = self.example_user('hamlet') do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR) self.assertTrue(user_profile.is_realm_admin) result = fetch_initial_state_data(user_profile, None, "", client_gravatar=False, user_avatar_url_field_optional=False) self.assertTrue(len(result['realm_bots']) > 2)
def test_realm_bots_non_admin(self) -> None: user_profile = self.example_user('cordelia') self.assertFalse(user_profile.is_realm_admin) result = fetch_initial_state_data(user_profile, None, "", client_gravatar=False, user_avatar_url_field_optional=False) self.assert_length(result['realm_bots'], 0) # additionally the API key for a random bot is not present in the data api_key = get_api_key(self.notification_bot()) self.assertNotIn(api_key, str(result))
def test_user_settings_based_on_client_capabilities(self) -> None: hamlet = self.example_user("hamlet") result = fetch_initial_state_data( user_profile=hamlet, user_settings_object=True, ) self.assertIn("user_settings", result) for prop in UserProfile.property_types: self.assertNotIn(prop, result) self.assertIn(prop, result["user_settings"]) result = fetch_initial_state_data( user_profile=hamlet, user_settings_object=False, ) self.assertIn("user_settings", result) for prop in UserProfile.property_types: if prop in { **UserProfile.display_settings_legacy, **UserProfile.notification_settings_legacy, }: # Only legacy settings are included in the top level. self.assertIn(prop, result) self.assertIn(prop, result["user_settings"])
def test_max_message_id_with_no_history(self) -> None: user_profile = self.example_user("aaron") # Delete all historical messages for this user UserMessage.objects.filter(user_profile=user_profile).delete() result = fetch_initial_state_data(user_profile) self.assertEqual(result["max_message_id"], -1)
def build_page_params_for_home_page_load( request: HttpRequest, user_profile: Optional[UserProfile], realm: Realm, insecure_desktop_app: bool, narrow: List[List[str]], narrow_stream: Optional[Stream], narrow_topic: Optional[str], first_in_realm: bool, prompt_for_invites: bool, needs_tutorial: bool, ) -> Tuple[int, Dict[str, Any]]: """ This function computes page_params for when we load the home page. The page_params data structure gets sent to the client. """ client_capabilities = { "notification_settings_null": True, "bulk_message_deletion": True, "user_avatar_url_field_optional": True, "stream_typing_notifications": False, # Set this to True when frontend support is implemented. "user_settings_object": True, } if user_profile is not None: client = RequestNotes.get_notes(request).client assert client is not None register_ret = do_events_register( user_profile, client, apply_markdown=True, client_gravatar=True, slim_presence=True, client_capabilities=client_capabilities, narrow=narrow, include_streams=False, ) else: # Since events for spectator is not implemented, we only fetch the data # at the time of request and don't register for any events. # TODO: Implement events for spectator. from zerver.lib.events import fetch_initial_state_data, post_process_state register_ret = fetch_initial_state_data( user_profile, realm=realm, event_types=None, queue_id=None, client_gravatar=False, user_avatar_url_field_optional=client_capabilities["user_avatar_url_field_optional"], user_settings_object=client_capabilities["user_settings_object"], slim_presence=False, include_subscribers=False, include_streams=False, ) post_process_state(user_profile, register_ret, False) furthest_read_time = get_furthest_read_time(user_profile) request_language = get_and_set_request_language( request, register_ret["user_settings"]["default_language"], translation.get_language_from_path(request.path_info), ) two_fa_enabled = settings.TWO_FACTOR_AUTHENTICATION_ENABLED and user_profile is not None billing_info = get_billing_info(user_profile) user_permission_info = get_user_permission_info(user_profile) # Pass parameters to the client-side JavaScript code. # These end up in a JavaScript Object named 'page_params'. page_params = dict( ## Server settings. test_suite=settings.TEST_SUITE, insecure_desktop_app=insecure_desktop_app, login_page=settings.HOME_NOT_LOGGED_IN, warn_no_email=settings.WARN_NO_EMAIL, search_pills_enabled=settings.SEARCH_PILLS_ENABLED, # Only show marketing email settings if on Zulip Cloud corporate_enabled=settings.CORPORATE_ENABLED, ## Misc. extra data. language_list=get_language_list(), needs_tutorial=needs_tutorial, first_in_realm=first_in_realm, prompt_for_invites=prompt_for_invites, furthest_read_time=furthest_read_time, bot_types=get_bot_types(user_profile), two_fa_enabled=two_fa_enabled, apps_page_url=get_apps_page_url(), show_billing=billing_info.show_billing, promote_sponsoring_zulip=promote_sponsoring_zulip_in_realm(realm), show_plans=billing_info.show_plans, show_webathena=user_permission_info.show_webathena, # Adding two_fa_enabled as condition saves us 3 queries when # 2FA is not enabled. two_fa_enabled_user=two_fa_enabled and bool(default_device(user_profile)), is_spectator=user_profile is None, # There is no event queue for spectators since # events support for spectators is not implemented yet. no_event_queue=user_profile is None, ) for field_name in register_ret.keys(): page_params[field_name] = register_ret[field_name] if narrow_stream is not None: # In narrow_stream context, initial pointer is just latest message recipient = narrow_stream.recipient try: max_message_id = ( Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id ) except IndexError: max_message_id = -1 page_params["narrow_stream"] = narrow_stream.name if narrow_topic is not None: page_params["narrow_topic"] = narrow_topic page_params["narrow"] = [dict(operator=term[0], operand=term[1]) for term in narrow] page_params["max_message_id"] = max_message_id assert isinstance(page_params["user_settings"], dict) page_params["user_settings"]["enable_desktop_notifications"] = False page_params["translation_data"] = get_language_translation_data(request_language) return register_ret["queue_id"], page_params
def test_realm_bots_admin(self) -> None: user_profile = self.example_user('hamlet') do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR) self.assertTrue(user_profile.is_realm_admin) result = fetch_initial_state_data(user_profile) self.assertTrue(len(result['realm_bots']) > 2)
def build_page_params_for_home_page_load( request: HttpRequest, user_profile: Optional[UserProfile], realm: Realm, insecure_desktop_app: bool, has_mobile_devices: bool, narrow: List[List[str]], narrow_stream: Optional[Stream], narrow_topic: Optional[str], first_in_realm: bool, prompt_for_invites: bool, needs_tutorial: bool, ) -> Tuple[int, Dict[str, Any]]: """ This function computes page_params for when we load the home page. The page_params data structure gets sent to the client. """ client_capabilities = { "notification_settings_null": True, "bulk_message_deletion": True, "user_avatar_url_field_optional": True, } if user_profile is not None: register_ret = do_events_register( user_profile, request.client, apply_markdown=True, client_gravatar=True, slim_presence=True, client_capabilities=client_capabilities, narrow=narrow, include_streams=False, ) else: # Since events for web_public_visitor is not implemented, we only fetch the data # at the time of request and don't register for any events. # TODO: Implement events for web_public_visitor. from zerver.lib.events import fetch_initial_state_data, post_process_state register_ret = fetch_initial_state_data( user_profile, event_types=None, queue_id=None, client_gravatar=False, user_avatar_url_field_optional=client_capabilities[ 'user_avatar_url_field_optional'], realm=realm, slim_presence=False, include_subscribers=False, include_streams=False) post_process_state(user_profile, register_ret, False) furthest_read_time = get_furthest_read_time(user_profile) request_language = get_and_set_request_language( request, register_ret['default_language'], translation.get_language_from_path(request.path_info)) two_fa_enabled = (settings.TWO_FACTOR_AUTHENTICATION_ENABLED and user_profile is not None) # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. debug_mode=settings.DEBUG, test_suite=settings.TEST_SUITE, poll_timeout=settings.POLL_TIMEOUT, insecure_desktop_app=insecure_desktop_app, login_page=settings.HOME_NOT_LOGGED_IN, root_domain_uri=settings.ROOT_DOMAIN_URI, save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, warn_no_email=settings.WARN_NO_EMAIL, search_pills_enabled=settings.SEARCH_PILLS_ENABLED, # Misc. extra data. initial_servertime=time.time( ), # Used for calculating relative presence age default_language_name=get_language_name( register_ret["default_language"]), language_list_dbl_col=get_language_list_for_templates( register_ret["default_language"]), language_list=get_language_list(), needs_tutorial=needs_tutorial, first_in_realm=first_in_realm, prompt_for_invites=prompt_for_invites, furthest_read_time=furthest_read_time, has_mobile_devices=has_mobile_devices, bot_types=get_bot_types(user_profile), two_fa_enabled=two_fa_enabled, # Adding two_fa_enabled as condition saves us 3 queries when # 2FA is not enabled. two_fa_enabled_user=two_fa_enabled and bool(default_device(user_profile)), is_web_public_visitor=user_profile is None, # There is no event queue for web_public_visitors since # events support for web_public_visitors is not implemented yet. no_event_queue=user_profile is None, ) for field_name in register_ret.keys(): page_params[field_name] = register_ret[field_name] if narrow_stream is not None: # In narrow_stream context, initial pointer is just latest message recipient = narrow_stream.recipient try: max_message_id = (Message.objects.filter( recipient=recipient).order_by("id").reverse()[0].id) except IndexError: max_message_id = -1 page_params["narrow_stream"] = narrow_stream.name if narrow_topic is not None: page_params["narrow_topic"] = narrow_topic page_params["narrow"] = [ dict(operator=term[0], operand=term[1]) for term in narrow ] page_params["max_message_id"] = max_message_id page_params["enable_desktop_notifications"] = False page_params["translation_data"] = get_language_translation_data( request_language) # Fetch data from the connected/logged in devices page_params["logged_in_devices"] = get_logged_in_devices() return register_ret["queue_id"], page_params