def handle(self, *args: Any, **options: str) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser stream_to_keep = get_stream(options["stream_to_keep"], realm) stream_to_destroy = get_stream(options["stream_to_destroy"], realm) recipient_to_destroy = get_stream_recipient(stream_to_destroy.id) recipient_to_keep = get_stream_recipient(stream_to_keep.id) # The high-level approach here is to move all the messages to # the surviving stream, deactivate all the subscriptions on # the stream to be removed and deactivate the stream, and add # new subscriptions to the stream to keep for any users who # were only on the now-deactivated stream. # Move the messages, and delete the old copies from caches. message_ids_to_clear = list( Message.objects.filter(recipient=recipient_to_destroy).values_list( "id", flat=True)) count = Message.objects.filter(recipient=recipient_to_destroy).update( recipient=recipient_to_keep) print("Moved %s messages" % (count, )) bulk_delete_cache_keys(message_ids_to_clear) # Move the Subscription objects. This algorithm doesn't # preserve any stream settings/colors/etc. from the stream # being destroyed, but it's convenient. existing_subs = Subscription.objects.filter( recipient=recipient_to_keep) users_already_subscribed = dict( (sub.user_profile_id, sub.active) for sub in existing_subs) subs_to_deactivate = Subscription.objects.filter( recipient=recipient_to_destroy, active=True) users_to_activate = [ sub.user_profile for sub in subs_to_deactivate if not users_already_subscribed.get(sub.user_profile_id, False) ] if len(subs_to_deactivate) > 0: print("Deactivating %s subscriptions" % (len(subs_to_deactivate), )) bulk_remove_subscriptions( [sub.user_profile for sub in subs_to_deactivate], [stream_to_destroy]) do_deactivate_stream(stream_to_destroy) if len(users_to_activate) > 0: print("Adding %s subscriptions" % (len(users_to_activate), )) bulk_add_subscriptions([stream_to_keep], users_to_activate)
def test_user_ids_muting_topic(self) -> None: hamlet = self.example_user('hamlet') cordelia = self.example_user('cordelia') realm = hamlet.realm stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) topic_name = 'teST topic' stream_topic_target = StreamTopicTarget( stream_id=stream.id, topic_name=topic_name, ) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, set()) def mute_user(user: UserProfile) -> None: add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name='test TOPIC', ) mute_user(hamlet) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, {hamlet.id}) mute_user(cordelia) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, {hamlet.id, cordelia.id})
def test_remove_muted_topic(self) -> None: user = self.example_user('hamlet') email = user.email realm = user.realm self.login(email) stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) url = '/api/v1/users/me/subscriptions/muted_topics' payloads = [ {'stream': stream.name, 'topic': 'vERONA3', 'op': 'remove'}, {'stream_id': stream.id, 'topic': 'vEroNA3', 'op': 'remove'}, ] for data in payloads: add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name='Verona3', ) self.assertIn([stream.name, 'Verona3'], get_topic_mutes(user)) result = self.api_patch(email, url, data) self.assert_json_success(result) self.assertNotIn([stream.name, 'Verona3'], get_topic_mutes(user)) self.assertFalse(topic_is_muted(user, stream.id, 'verona3'))
def test_muted_topic_add_invalid(self) -> None: user = self.example_user('hamlet') email = user.email realm = user.realm self.login(email) stream = get_stream('Verona', realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=u'Verona3', ) url = '/api/v1/users/me/subscriptions/muted_topics' data = {'stream': stream.name, 'topic': 'Verona3', 'op': 'add'} # type: Dict[str, Any] result = self.api_patch(email, url, data) self.assert_json_error(result, "Topic already muted") data = {'stream_id': 999999999, 'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Invalid stream id") data = {'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Please supply 'stream'.") data = {'stream': stream.name, 'stream_id': stream.id, 'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Please choose one: 'stream' or 'stream_id'.")
def access_stream_common(user_profile, stream, error): # type: (UserProfile, Stream, Text) -> Tuple[Recipient, Subscription] """Common function for backend code where the target use attempts to access the target stream, returning all the data fetched along the way. If that user does not have permission to access that stream, we throw an exception. A design goal is that the error message is the same for streams you can't access and streams that don't exist.""" # First, we don't allow any access to streams in other realms. if stream.realm_id != user_profile.realm_id: raise JsonableError(error) recipient = get_stream_recipient(stream.id) try: sub = Subscription.objects.get(user_profile=user_profile, recipient=recipient, active=True) except Subscription.DoesNotExist: sub = None # If the stream is in your realm and public, you can access it. if stream.is_public(): return (recipient, sub) # Or if you are subscribed to the stream, you can access it. if sub is not None: return (recipient, sub) # Otherwise it is a private stream and you're not on it, so throw # an error. raise JsonableError(error)
def access_stream_common( user_profile: UserProfile, stream: Stream, error: Text, require_active: bool = True) -> Tuple[Recipient, Subscription]: """Common function for backend code where the target use attempts to access the target stream, returning all the data fetched along the way. If that user does not have permission to access that stream, we throw an exception. A design goal is that the error message is the same for streams you can't access and streams that don't exist.""" # First, we don't allow any access to streams in other realms. if stream.realm_id != user_profile.realm_id: raise JsonableError(error) recipient = get_stream_recipient(stream.id) try: sub = Subscription.objects.get(user_profile=user_profile, recipient=recipient, active=require_active) except Subscription.DoesNotExist: sub = None # If the stream is in your realm and public, you can access it. if stream.is_public(): return (recipient, sub) # Or if you are subscribed to the stream, you can access it. if sub is not None: return (recipient, sub) # Otherwise it is a private stream and you're not on it, so throw # an error. raise JsonableError(error)
def mute_stream(stream_name: str) -> None: stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) subscription = Subscription.objects.get(user_profile=user, recipient=recipient) subscription.in_home_view = False subscription.save()
def mute_stream(stream_name: str) -> None: stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) subscription = Subscription.objects.get( user_profile=user, recipient=recipient ) subscription.in_home_view = False subscription.save()
def mute_topic(stream_name: str, topic_name: str) -> None: stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def mute_topic(stream_name: str, topic_name: str) -> None: stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def handle(self, *args: Any, **options: str) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser stream_to_keep = get_stream(options["stream_to_keep"], realm) stream_to_destroy = get_stream(options["stream_to_destroy"], realm) recipient_to_destroy = get_stream_recipient(stream_to_destroy.id) recipient_to_keep = get_stream_recipient(stream_to_keep.id) # The high-level approach here is to move all the messages to # the surviving stream, deactivate all the subscriptions on # the stream to be removed and deactivate the stream, and add # new subscriptions to the stream to keep for any users who # were only on the now-deactivated stream. # Move the messages, and delete the old copies from caches. message_ids_to_clear = list(Message.objects.filter( recipient=recipient_to_destroy).values_list("id", flat=True)) count = Message.objects.filter(recipient=recipient_to_destroy).update(recipient=recipient_to_keep) print("Moved %s messages" % (count,)) bulk_delete_cache_keys(message_ids_to_clear) # Move the Subscription objects. This algorithm doesn't # preserve any stream settings/colors/etc. from the stream # being destroyed, but it's convenient. existing_subs = Subscription.objects.filter(recipient=recipient_to_keep) users_already_subscribed = dict((sub.user_profile_id, sub.active) for sub in existing_subs) subs_to_deactivate = Subscription.objects.filter(recipient=recipient_to_destroy, active=True) users_to_activate = [ sub.user_profile for sub in subs_to_deactivate if not users_already_subscribed.get(sub.user_profile_id, False) ] if len(subs_to_deactivate) > 0: print("Deactivating %s subscriptions" % (len(subs_to_deactivate),)) bulk_remove_subscriptions([sub.user_profile for sub in subs_to_deactivate], [stream_to_destroy], self.get_client()) do_deactivate_stream(stream_to_destroy) if len(users_to_activate) > 0: print("Adding %s subscriptions" % (len(users_to_activate),)) bulk_add_subscriptions([stream_to_keep], users_to_activate)
def mute_topic(stream_name, topic_name): # type: (Text, Text) -> None stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def mute_topic(stream_name, topic_name): # type: (Text, Text) -> None stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def get_web_public_topics_backend(request: HttpRequest, stream_id: int) -> HttpResponse: try: stream = get_stream_by_id(stream_id) except JsonableError: return json_success(dict(topics=[])) if not stream.is_web_public: return json_success(dict(topics=[])) recipient = get_stream_recipient(stream.id) result = get_topic_history_for_web_public_stream(recipient=recipient) return json_success(dict(topics=result))
def get_web_public_topics_backend(request: HttpRequest, stream_id: int) -> HttpResponse: try: stream = get_stream_by_id(stream_id) except JsonableError: return json_success(dict(topics=[])) if not stream.is_web_public: return json_success(dict(topics=[])) recipient = get_stream_recipient(stream.id) result = get_topic_history_for_web_public_stream(recipient=recipient) return json_success(dict(topics=result))
def _turn_on_stream_push_for_cordelia(self) -> None: ''' conventions: Cordelia is the message receiver we care about. Scotland is our stream. ''' cordelia = self.example_user('cordelia') stream = self.subscribe(cordelia, 'Scotland') recipient = get_stream_recipient(stream.id) cordelia_subscription = Subscription.objects.get( user_profile_id=cordelia.id, recipient=recipient, ) cordelia_subscription.push_notifications = True cordelia_subscription.save()
def _turn_on_stream_push_for_cordelia(self) -> None: ''' conventions: Cordelia is the message receiver we care about. Scotland is our stream. ''' cordelia = self.example_user('cordelia') stream = self.subscribe(cordelia, 'Scotland') recipient = get_stream_recipient(stream.id) cordelia_subscription = Subscription.objects.get( user_profile_id=cordelia.id, recipient=recipient, ) cordelia_subscription.push_notifications = True cordelia_subscription.save()
def set_topic_mutes(user_profile: UserProfile, muted_topics: List[List[str]]) -> None: ''' This is only used in tests. ''' MutedTopic.objects.filter(user_profile=user_profile, ).delete() for stream_name, topic_name in muted_topics: stream = get_stream(stream_name, user_profile.realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user_profile, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def access_stream_common( user_profile: UserProfile, stream: Stream, error: str, require_active: bool = True, allow_realm_admin: bool = False ) -> Tuple[Recipient, Optional[Subscription]]: """Common function for backend code where the target use attempts to access the target stream, returning all the data fetched along the way. If that user does not have permission to access that stream, we throw an exception. A design goal is that the error message is the same for streams you can't access and streams that don't exist.""" # First, we don't allow any access to streams in other realms. if stream.realm_id != user_profile.realm_id: raise JsonableError(error) recipient = get_stream_recipient(stream.id) try: sub = Subscription.objects.get(user_profile=user_profile, recipient=recipient, active=require_active) except Subscription.DoesNotExist: sub = None # If the stream is in your realm and public, you can access it. if stream.is_public() and not user_profile.is_guest: return (recipient, sub) # Or if you are subscribed to the stream, you can access it. if sub is not None: return (recipient, sub) # For some specific callers (e.g. getting list of subscribers, # removing other users from a stream, and updating stream name and # description), we allow realm admins to access stream even if # they are not subscribed to a private stream. if user_profile.is_realm_admin and allow_realm_admin: return (recipient, sub) # Otherwise it is a private stream and you're not on it, so throw # an error. raise JsonableError(error)
def test_muted_topic_add_invalid(self) -> None: self.user_profile = self.example_user('hamlet') email = self.user_profile.email self.login(email) realm = self.user_profile.realm stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=self.user_profile, stream_id=stream.id, recipient_id=recipient.id, topic_name=u'Verona3', ) url = '/api/v1/users/me/subscriptions/muted_topics' data = {'stream': 'Verona', 'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Topic already muted")
def test_muted_topic_add_invalid(self) -> None: user = self.example_user('hamlet') email = user.email realm = user.realm self.login(email) stream = get_stream('Verona', realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name=u'Verona3', date_muted=timezone_now(), ) url = '/api/v1/users/me/subscriptions/muted_topics' data = { 'stream': stream.name, 'topic': 'Verona3', 'op': 'add' } # type: Dict[str, Any] result = self.api_patch(email, url, data) self.assert_json_error(result, "Topic already muted") data = {'stream_id': 999999999, 'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Invalid stream id") data = {'topic': 'Verona3', 'op': 'add'} result = self.api_patch(email, url, data) self.assert_json_error(result, "Please supply 'stream'.") data = { 'stream': stream.name, 'stream_id': stream.id, 'topic': 'Verona3', 'op': 'add' } result = self.api_patch(email, url, data) self.assert_json_error(result, "Please choose one: 'stream' or 'stream_id'.")
def set_topic_mutes(user_profile: UserProfile, muted_topics: List[List[str]]) -> None: ''' This is only used in tests. ''' MutedTopic.objects.filter( user_profile=user_profile, ).delete() for stream_name, topic_name in muted_topics: stream = get_stream(stream_name, user_profile.realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user_profile, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, )
def access_stream_common(user_profile: UserProfile, stream: Stream, error: str, require_active: bool=True, allow_realm_admin: bool=False) -> Tuple[Recipient, Optional[Subscription]]: """Common function for backend code where the target use attempts to access the target stream, returning all the data fetched along the way. If that user does not have permission to access that stream, we throw an exception. A design goal is that the error message is the same for streams you can't access and streams that don't exist.""" # First, we don't allow any access to streams in other realms. if stream.realm_id != user_profile.realm_id: raise JsonableError(error) recipient = get_stream_recipient(stream.id) try: sub = Subscription.objects.get(user_profile=user_profile, recipient=recipient, active=require_active) except Subscription.DoesNotExist: sub = None # If the stream is in your realm and public, you can access it. if stream.is_public() and not user_profile.is_guest: return (recipient, sub) # Or if you are subscribed to the stream, you can access it. if sub is not None: return (recipient, sub) # For some specific callers (e.g. getting list of subscribers, # removing other users from a stream, and updating stream name and # description), we allow realm admins to access stream even if # they are not subscribed to a private stream. if user_profile.is_realm_admin and allow_realm_admin: return (recipient, sub) # Otherwise it is a private stream and you're not on it, so throw # an error. raise JsonableError(error)
def send_zulip(sender: str, stream: Stream, topic: str, content: str) -> None: # Truncate the topic truncated_topic = truncate_topic(topic) # If the topic was truncated, add the topic to the front of the message if (len(truncated_topic) < len(topic) and not Message.objects.filter( subject=truncate_topic(topic), recipient=get_stream_recipient(stream.id), date_sent__lte=datetime.datetime.today(), date_sent__gt=datetime.datetime.today() - datetime.timedelta(days=7) ).exists()): content = "Subject: {}\n\n{}".format(topic, content) internal_send_message( stream.realm, sender, "stream", stream.name, truncated_topic, truncate_body(content), email_gateway=True)
def test_user_ids_muting_topic(self) -> None: hamlet = self.example_user('hamlet') cordelia = self.example_user('cordelia') realm = hamlet.realm stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) topic_name = 'teST topic' stream_topic_target = StreamTopicTarget( stream_id=stream.id, topic_name=topic_name, ) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, set()) def mute_user(user: UserProfile) -> None: add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name='test TOPIC', date_muted=timezone_now(), ) mute_user(hamlet) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, {hamlet.id}) hamlet_date_muted = MutedTopic.objects.filter( user_profile=hamlet)[0].date_muted self.assertTrue( timezone_now() - hamlet_date_muted <= timedelta(seconds=100)) mute_user(cordelia) user_ids = stream_topic_target.user_ids_muting_topic() self.assertEqual(user_ids, {hamlet.id, cordelia.id}) cordelia_date_muted = MutedTopic.objects.filter( user_profile=cordelia)[0].date_muted self.assertTrue( timezone_now() - cordelia_date_muted <= timedelta(seconds=100))
def test_remove_muted_topic(self) -> None: self.user_profile = self.example_user('hamlet') email = self.user_profile.email self.login(email) realm = self.user_profile.realm stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=self.user_profile, stream_id=stream.id, recipient_id=recipient.id, topic_name=u'Verona3', ) url = '/api/v1/users/me/subscriptions/muted_topics' data = {'stream': 'Verona', 'topic': 'vERONA3', 'op': 'remove'} result = self.api_patch(email, url, data) self.assert_json_success(result) user = self.example_user('hamlet') self.assertNotIn([[u'Verona', u'Verona3']], get_topic_mutes(user))
def test_remove_muted_topic(self) -> None: user = self.example_user('hamlet') email = user.email realm = user.realm self.login(email) stream = get_stream(u'Verona', realm) recipient = get_stream_recipient(stream.id) url = '/api/v1/users/me/subscriptions/muted_topics' payloads = [ { 'stream': stream.name, 'topic': 'vERONA3', 'op': 'remove' }, { 'stream_id': stream.id, 'topic': 'vEroNA3', 'op': 'remove' }, ] for data in payloads: add_topic_mute( user_profile=user, stream_id=stream.id, recipient_id=recipient.id, topic_name='Verona3', date_muted=timezone_now(), ) self.assertIn([stream.name, 'Verona3'], get_topic_mutes(user)) result = self.api_patch(email, url, data) self.assert_json_success(result) self.assertNotIn([stream.name, 'Verona3'], get_topic_mutes(user)) self.assertFalse(topic_is_muted(user, stream.id, 'verona3'))
def set_topic_mutes(user_profile: UserProfile, muted_topics: List[List[str]], date_muted: Optional[datetime.datetime]=None) -> None: ''' This is only used in tests. ''' MutedTopic.objects.filter( user_profile=user_profile, ).delete() if date_muted is None: date_muted = timezone_now() for stream_name, topic_name in muted_topics: stream = get_stream(stream_name, user_profile.realm) recipient = get_stream_recipient(stream.id) add_topic_mute( user_profile=user_profile, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, date_muted=date_muted, )
def test_stream_recipient_info(self) -> None: hamlet = self.example_user('hamlet') cordelia = self.example_user('cordelia') othello = self.example_user('othello') realm = hamlet.realm stream_name = 'Test Stream' topic_name = 'test topic' for user in [hamlet, cordelia, othello]: self.subscribe(user, stream_name) stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) stream_topic = StreamTopicTarget( stream_id=stream.id, topic_name=topic_name, ) sub = get_subscription(stream_name, hamlet) sub.push_notifications = True sub.save() info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, ) all_user_ids = {hamlet.id, cordelia.id, othello.id} expected_info = dict( active_user_ids=all_user_ids, push_notify_user_ids=set(), stream_push_user_ids={hamlet.id}, stream_email_user_ids=set(), um_eligible_user_ids=all_user_ids, long_term_idle_user_ids=set(), default_bot_user_ids=set(), service_bot_tuples=[], ) self.assertEqual(info, expected_info) # Now mute Hamlet to omit him from stream_push_user_ids. add_topic_mute( user_profile=hamlet, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, ) info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, ) self.assertEqual(info['stream_push_user_ids'], set()) # Add a service bot. service_bot = do_create_user( email='*****@*****.**', password='', realm=realm, full_name='', short_name='', bot_type=UserProfile.EMBEDDED_BOT, ) info = get_recipient_info(recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, possibly_mentioned_user_ids={service_bot.id}) self.assertEqual(info['service_bot_tuples'], [ (service_bot.id, UserProfile.EMBEDDED_BOT), ]) # Add a normal bot. normal_bot = do_create_user( email='*****@*****.**', password='', realm=realm, full_name='', short_name='', bot_type=UserProfile.DEFAULT_BOT, ) info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, possibly_mentioned_user_ids={service_bot.id, normal_bot.id}) self.assertEqual(info['default_bot_user_ids'], {normal_bot.id})
def home_real(request: HttpRequest) -> HttpResponse: # We need to modify the session object every two weeks or it will expire. # This line makes reloading the page a sufficient action to keep the # session alive. request.session.modified = True user_profile = request.user # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[str]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name(user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing exception", extra=dict(request=request)) if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, client_gravatar=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: # nocoverage # TODO: Look into the history of last_reminder; we may have # eliminated that as a useful concept for non-bot users. user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: latest_read = get_usermessage_by_message_id(user_profile, user_profile.pointer) if latest_read is None: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) # We pick a language for the user as follows: # * First priority is the language in the URL, for debugging. # * If not in the URL, we use the language from the user's settings. request_language = translation.get_language_from_path(request.path_info) if request_language is None: request_language = register_ret['default_language'] translation.activate(request_language) # We also save the language to the user's session, so that # something reasonable will happen in logged-in portico pages. request.session[ translation.LANGUAGE_SESSION_KEY] = translation.get_language() two_fa_enabled = settings.TWO_FACTOR_AUTHENTICATION_ENABLED # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. development_environment=settings.DEVELOPMENT, debug_mode=settings.DEBUG, test_suite=settings.TEST_SUITE, poll_timeout=settings.POLL_TIMEOUT, login_page=settings.HOME_NOT_LOGGED_IN, root_domain_uri=settings.ROOT_DOMAIN_URI, maxfilesize=settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size=settings.MAX_AVATAR_FILE_SIZE, server_generation=settings.SERVER_GENERATION, use_websockets=settings.USE_WEBSOCKETS, save_stacktraces=settings.SAVE_FRONTEND_STACKTRACES, warn_no_email=settings.WARN_NO_EMAIL, server_inline_image_preview=settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview=settings.INLINE_URL_EMBED_PREVIEW, password_min_length=settings.PASSWORD_MIN_LENGTH, password_min_guesses=settings.PASSWORD_MIN_GUESSES, jitsi_server_url=settings.JITSI_SERVER_URL, search_pills_enabled=settings.SEARCH_PILLS_ENABLED, # Misc. extra data. have_initial_messages=user_has_messages, 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=sent_time_in_epoch_seconds(latest_read), has_mobile_devices=num_push_devices_for_user(user_profile) > 0, 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)), ) undesired_register_ret_fields = [ 'streams', ] for field_name in set( register_ret.keys()) - set(undesired_register_ret_fields): 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 = get_stream_recipient(narrow_stream.id) try: initial_pointer = Message.objects.filter( recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -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"] = initial_pointer page_params["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False if user_profile.is_guest: show_invites = False show_billing = False show_plans = False if settings.CORPORATE_ENABLED: from corporate.models import Customer if user_profile.is_billing_admin or user_profile.is_realm_admin: customer = Customer.objects.filter( realm=user_profile.realm).first() if customer is not None and customer.has_billing_relationship: show_billing = True if user_profile.realm.plan_type == Realm.LIMITED: show_plans = True request._log_data['extra'] = "[%s]" % (register_ret["queue_id"], ) page_params['translation_data'] = {} if request_language != 'en': page_params['translation_data'] = get_language_translation_data( request_language) csp_nonce = generate_random_token(48) emojiset = user_profile.emojiset if emojiset == UserProfile.TEXT_EMOJISET: # If current emojiset is `TEXT_EMOJISET`, then fallback to # GOOGLE_EMOJISET for picking which spritesheet's CSS to # include (and thus how to display emojis in the emoji picker # and composebox typeahead). emojiset = UserProfile.GOOGLE_BLOB_EMOJISET response = render( request, 'zerver/app/index.html', context={ 'user_profile': user_profile, 'emojiset': emojiset, 'page_params': JSONEncoderForHTML().encode(page_params), 'csp_nonce': csp_nonce, 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'search_pills_enabled': settings.SEARCH_PILLS_ENABLED, 'show_invites': show_invites, 'show_billing': show_billing, 'show_plans': show_plans, 'is_admin': user_profile.is_realm_admin, 'is_guest': user_profile.is_guest, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, }, ) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def home_real(request): # type: (HttpRequest) -> HttpResponse # We need to modify the session object every two weeks or it will expire. # This line makes reloading the page a sufficient action to keep the # session alive. request.session.modified = True user_profile = request.user # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[Text]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name( user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing") if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: try: latest_read = UserMessage.objects.get(user_profile=user_profile, message__id=user_profile.pointer) except UserMessage.DoesNotExist: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) latest_read = None # Set default language and make it persist default_language = register_ret['default_language'] url_lang = '/{}'.format(request.LANGUAGE_CODE) if not request.path.startswith(url_lang): translation.activate(default_language) request.session[translation.LANGUAGE_SESSION_KEY] = translation.get_language() # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. development_environment = settings.DEVELOPMENT, debug_mode = settings.DEBUG, test_suite = settings.TEST_SUITE, poll_timeout = settings.POLL_TIMEOUT, login_page = settings.HOME_NOT_LOGGED_IN, root_domain_uri = settings.ROOT_DOMAIN_URI, maxfilesize = settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size = settings.MAX_AVATAR_FILE_SIZE, server_generation = settings.SERVER_GENERATION, use_websockets = settings.USE_WEBSOCKETS, save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, server_inline_image_preview = settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview = settings.INLINE_URL_EMBED_PREVIEW, password_min_length = settings.PASSWORD_MIN_LENGTH, password_min_guesses = settings.PASSWORD_MIN_GUESSES, # Misc. extra data. have_initial_messages = user_has_messages, 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 = sent_time_in_epoch_seconds(latest_read), has_mobile_devices = num_push_devices_for_user(user_profile) > 0, ) undesired_register_ret_fields = [ 'streams', ] for field_name in set(register_ret.keys()) - set(undesired_register_ret_fields): 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 = get_stream_recipient(narrow_stream.id) try: initial_pointer = Message.objects.filter(recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -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"] = initial_pointer page_params["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) response = render(request, 'zerver/index.html', context={'user_profile': user_profile, 'page_params': simplejson.encoder.JSONEncoderForHTML().encode(page_params), 'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")), 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'show_invites': show_invites, 'is_admin': user_profile.is_realm_admin, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, },) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def get_recipient_stream(r: Realm) -> Stream: return get_stream_recipient( Stream.objects.get(name='Verona', realm=r).id)
def test_import_realm(self) -> None: original_realm = Realm.objects.get(string_id='zulip') RealmEmoji.objects.get(realm=original_realm).delete() # data to test import of huddles huddle = [self.example_email('hamlet'), self.example_email('othello')] self.send_huddle_message(self.example_email('cordelia'), huddle, 'test huddle message') # data to test import of hotspots sample_user = self.example_user('hamlet') UserHotspot.objects.create(user=sample_user, hotspot='intro_streams') # data to test import of muted topic stream = get_stream(u'Verona', original_realm) add_topic_mute(user_profile=sample_user, stream_id=stream.id, recipient_id=get_stream_recipient(stream.id).id, topic_name=u'Verona2') # data to test import of botstoragedata and botconfigdata bot_profile = do_create_user(email="*****@*****.**", password="******", realm=original_realm, full_name="bot", short_name="bot", bot_type=UserProfile.EMBEDDED_BOT, bot_owner=sample_user) storage = StateHandler(bot_profile) storage.put('some key', 'some value') set_bot_config(bot_profile, 'entry 1', 'value 1') self._export_realm(original_realm) with patch('logging.info'): with self.settings(BILLING_ENABLED=False): do_import_realm('var/test-export', 'test-zulip') # sanity checks # test realm self.assertTrue(Realm.objects.filter(string_id='test-zulip').exists()) imported_realm = Realm.objects.get(string_id='test-zulip') self.assertNotEqual(imported_realm.id, original_realm.id) def assert_realm_values(f: Callable[[Realm], Any], equal: bool = True) -> None: orig_realm_result = f(original_realm) imported_realm_result = f(imported_realm) # orig_realm_result should be truthy and have some values, otherwise # the test is kind of meaningless assert (orig_realm_result) if equal: self.assertEqual(orig_realm_result, imported_realm_result) else: self.assertNotEqual(orig_realm_result, imported_realm_result) # test users assert_realm_values( lambda r: {user.email for user in r.get_admin_users()}) assert_realm_values( lambda r: {user.email for user in r.get_active_users()}) # test stream assert_realm_values( lambda r: {stream.name for stream in get_active_streams(r)}) # test recipients def get_recipient_stream(r: Realm) -> Stream: return get_stream_recipient( Stream.objects.get(name='Verona', realm=r).id) def get_recipient_user(r: Realm) -> UserProfile: return get_personal_recipient( UserProfile.objects.get(full_name='Iago', realm=r).id) assert_realm_values(lambda r: get_recipient_stream(r).type) assert_realm_values(lambda r: get_recipient_user(r).type) # test subscription def get_subscribers(recipient: Recipient) -> Set[str]: subscriptions = Subscription.objects.filter(recipient=recipient) users = {sub.user_profile.email for sub in subscriptions} return users assert_realm_values(lambda r: get_subscribers(get_recipient_stream(r))) assert_realm_values(lambda r: get_subscribers(get_recipient_user(r))) # test custom profile fields def get_custom_profile_field_names(r: Realm) -> Set[str]: custom_profile_fields = CustomProfileField.objects.filter(realm=r) custom_profile_field_names = { field.name for field in custom_profile_fields } return custom_profile_field_names assert_realm_values(get_custom_profile_field_names) def get_custom_profile_with_field_type_user( r: Realm) -> Tuple[Set[Any], Set[Any], Set[FrozenSet[str]]]: fields = CustomProfileField.objects.filter( field_type=CustomProfileField.USER, realm=r) def get_email(user_id: int) -> str: return UserProfile.objects.get(id=user_id).email def get_email_from_value( field_value: CustomProfileFieldValue) -> Set[str]: user_id_list = ujson.loads(field_value.value) return {get_email(user_id) for user_id in user_id_list} def custom_profile_field_values_for( fields: List[CustomProfileField]) -> Set[FrozenSet[str]]: user_emails = set() # type: Set[FrozenSet[str]] for field in fields: values = CustomProfileFieldValue.objects.filter( field=field) for value in values: user_emails.add(frozenset(get_email_from_value(value))) return user_emails field_names, field_hints = (set() for i in range(2)) for field in fields: field_names.add(field.name) field_hints.add(field.hint) return (field_hints, field_names, custom_profile_field_values_for(fields)) assert_realm_values(get_custom_profile_with_field_type_user) # test realmauditlog def get_realm_audit_log_event_type(r: Realm) -> Set[str]: realmauditlogs = RealmAuditLog.objects.filter(realm=r).exclude( event_type=RealmAuditLog.REALM_PLAN_TYPE_CHANGED) realmauditlog_event_type = { log.event_type for log in realmauditlogs } return realmauditlog_event_type assert_realm_values(get_realm_audit_log_event_type) # test huddles def get_huddle_hashes(r: str) -> str: short_names = ['cordelia', 'hamlet', 'othello'] user_id_list = [ UserProfile.objects.get(realm=r, short_name=name).id for name in short_names ] huddle_hash = get_huddle_hash(user_id_list) return huddle_hash assert_realm_values(get_huddle_hashes, equal=False) def get_huddle_message(r: str) -> str: huddle_hash = get_huddle_hashes(r) huddle_id = Huddle.objects.get(huddle_hash=huddle_hash).id huddle_recipient = Recipient.objects.get(type_id=huddle_id, type=3) huddle_message = Message.objects.get(recipient=huddle_recipient) return huddle_message.content assert_realm_values(get_huddle_message) self.assertEqual(get_huddle_message(imported_realm), 'test huddle message') # test userhotspot def get_user_hotspots(r: str) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') hotspots = UserHotspot.objects.filter(user=user_profile) user_hotspots = {hotspot.hotspot for hotspot in hotspots} return user_hotspots assert_realm_values(get_user_hotspots) # test muted topics def get_muted_topics(r: Realm) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') muted_topics = MutedTopic.objects.filter(user_profile=user_profile) topic_names = { muted_topic.topic_name for muted_topic in muted_topics } return topic_names assert_realm_values(get_muted_topics) # test usergroups assert_realm_values( lambda r: {group.name for group in UserGroup.objects.filter(realm=r)}) def get_user_membership(r: str) -> Set[str]: usergroup = UserGroup.objects.get(realm=r, name='hamletcharacters') usergroup_membership = UserGroupMembership.objects.filter( user_group=usergroup) users = { membership.user_profile.email for membership in usergroup_membership } return users assert_realm_values(get_user_membership) # test botstoragedata and botconfigdata def get_botstoragedata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_storage_data = BotStorageData.objects.get( bot_profile=bot_profile) return { 'key': bot_storage_data.key, 'data': bot_storage_data.value } assert_realm_values(get_botstoragedata) def get_botconfigdata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_config_data = BotConfigData.objects.get( bot_profile=bot_profile) return {'key': bot_config_data.key, 'data': bot_config_data.value} assert_realm_values(get_botconfigdata) # test messages def get_stream_messages(r: Realm) -> Message: recipient = get_recipient_stream(r) messages = Message.objects.filter(recipient=recipient) return messages def get_stream_topics(r: Realm) -> Set[str]: messages = get_stream_messages(r) topics = {m.topic_name() for m in messages} return topics assert_realm_values(get_stream_topics) # test usermessages def get_usermessages_user(r: Realm) -> Set[Any]: messages = get_stream_messages(r).order_by('content') usermessage = UserMessage.objects.filter(message=messages[0]) usermessage_user = {um.user_profile.email for um in usermessage} return usermessage_user assert_realm_values(get_usermessages_user)
def home_real(request: HttpRequest) -> HttpResponse: # We need to modify the session object every two weeks or it will expire. # This line makes reloading the page a sufficient action to keep the # session alive. request.session.modified = True user_profile = request.user # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[str]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name( user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing exception", extra=dict(request=request)) if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, client_gravatar=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: # nocoverage # TODO: Look into the history of last_reminder; we may have # eliminated that as a useful concept for non-bot users. user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: latest_read = get_usermessage_by_message_id(user_profile, user_profile.pointer) if latest_read is None: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) # We pick a language for the user as follows: # * First priority is the language in the URL, for debugging. # * If not in the URL, we use the language from the user's settings. request_language = translation.get_language_from_path(request.path_info) if request_language is None: request_language = register_ret['default_language'] translation.activate(request_language) # We also save the language to the user's session, so that # something reasonable will happen in logged-in portico pages. request.session[translation.LANGUAGE_SESSION_KEY] = translation.get_language() two_fa_enabled = settings.TWO_FACTOR_AUTHENTICATION_ENABLED # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. development_environment = settings.DEVELOPMENT, debug_mode = settings.DEBUG, test_suite = settings.TEST_SUITE, poll_timeout = settings.POLL_TIMEOUT, login_page = settings.HOME_NOT_LOGGED_IN, root_domain_uri = settings.ROOT_DOMAIN_URI, maxfilesize = settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size = settings.MAX_AVATAR_FILE_SIZE, server_generation = settings.SERVER_GENERATION, use_websockets = settings.USE_WEBSOCKETS, save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, warn_no_email = settings.WARN_NO_EMAIL, server_inline_image_preview = settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview = settings.INLINE_URL_EMBED_PREVIEW, password_min_length = settings.PASSWORD_MIN_LENGTH, password_min_guesses = settings.PASSWORD_MIN_GUESSES, jitsi_server_url = settings.JITSI_SERVER_URL, search_pills_enabled = settings.SEARCH_PILLS_ENABLED, # Misc. extra data. have_initial_messages = user_has_messages, 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 = sent_time_in_epoch_seconds(latest_read), has_mobile_devices = num_push_devices_for_user(user_profile) > 0, 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)), ) undesired_register_ret_fields = [ 'streams', ] for field_name in set(register_ret.keys()) - set(undesired_register_ret_fields): 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 = get_stream_recipient(narrow_stream.id) try: initial_pointer = Message.objects.filter(recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -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"] = initial_pointer page_params["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False if user_profile.is_guest: show_invites = False show_billing = False show_plans = False if settings.CORPORATE_ENABLED: from corporate.models import Customer if user_profile.is_billing_admin or user_profile.is_realm_admin: customer = Customer.objects.filter(realm=user_profile.realm).first() if customer is not None and customer.has_billing_relationship: show_billing = True if user_profile.realm.plan_type == Realm.LIMITED: show_plans = True request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) page_params['translation_data'] = {} if request_language != 'en': page_params['translation_data'] = get_language_translation_data(request_language) csp_nonce = generate_random_token(48) emojiset = user_profile.emojiset if emojiset == UserProfile.TEXT_EMOJISET: # If current emojiset is `TEXT_EMOJISET`, then fallback to # GOOGLE_EMOJISET for picking which spritesheet's CSS to # include (and thus how to display emojis in the emoji picker # and composebox typeahead). emojiset = UserProfile.GOOGLE_BLOB_EMOJISET response = render(request, 'zerver/app/index.html', context={'user_profile': user_profile, 'emojiset': emojiset, 'page_params': JSONEncoderForHTML().encode(page_params), 'csp_nonce': csp_nonce, 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'search_pills_enabled': settings.SEARCH_PILLS_ENABLED, 'show_invites': show_invites, 'show_billing': show_billing, 'show_plans': show_plans, 'is_admin': user_profile.is_realm_admin, 'is_guest': user_profile.is_guest, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, 'invite_as': PreregistrationUser.INVITE_AS, },) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def test_import_realm(self) -> None: original_realm = Realm.objects.get(string_id='zulip') RealmEmoji.objects.get(realm=original_realm).delete() self._export_realm(original_realm) with patch('logging.info'): do_import_realm('var/test-export', 'test-zulip') # sanity checks # test realm self.assertTrue(Realm.objects.filter(string_id='test-zulip').exists()) imported_realm = Realm.objects.get(string_id='test-zulip') realms = [original_realm, imported_realm] self.assertNotEqual(imported_realm.id, original_realm.id) # test users emails = [{user.email for user in realm.get_admin_users()} for realm in realms] self.assertEqual(emails[0], emails[1]) emails = [{ user.email for user in realm.get_active_users().filter(is_bot=False) } for realm in realms] self.assertEqual(emails[0], emails[1]) # test stream stream_names = [{stream.name for stream in get_active_streams(realm)} for realm in realms] self.assertEqual(stream_names[0], stream_names[1]) # test recipients stream_recipients = [ get_stream_recipient( Stream.objects.get(name='Verona', realm=realm).id) for realm in realms ] self.assertEqual(stream_recipients[0].type, stream_recipients[1].type) user_recipients = [ get_personal_recipient( UserProfile.objects.get(full_name='Iago', realm=realm).id) for realm in realms ] self.assertEqual(user_recipients[0].type, user_recipients[1].type) # test subscription stream_subscription = [ Subscription.objects.filter(recipient=recipient) for recipient in stream_recipients ] subscription_stream_user = [{ sub.user_profile.email for sub in subscription } for subscription in stream_subscription] self.assertEqual(subscription_stream_user[0], subscription_stream_user[1]) user_subscription = [ Subscription.objects.filter(recipient=recipient) for recipient in user_recipients ] subscription_user = [{sub.user_profile.email for sub in subscription} for subscription in user_subscription] self.assertEqual(subscription_user[0], subscription_user[1]) # test custom profile fields custom_profile_field = [ CustomProfileField.objects.filter(realm=realm) for realm in realms ] custom_profile_field_name = [{ custom_profile_field.name for custom_profile_field in realm_custom_profile_field } for realm_custom_profile_field in custom_profile_field] self.assertEqual(custom_profile_field_name[0], custom_profile_field_name[1]) # test messages stream_message = [ Message.objects.filter(recipient=recipient) for recipient in stream_recipients ] stream_message_subject = [{ message.subject for message in stream_message } for stream_message in stream_message] self.assertEqual(stream_message_subject[0], stream_message_subject[1]) # test usermessages stream_message = [ stream_message.order_by('content') for stream_message in stream_message ] usermessage = [ UserMessage.objects.filter(message=stream_message[0]) for stream_message in stream_message ] usermessage_user = [{ user_message.user_profile.email for user_message in usermessage } for usermessage in usermessage] self.assertEqual(usermessage_user[0], usermessage_user[1])
def home_real(request: HttpRequest) -> HttpResponse: # We need to modify the session object every two weeks or it will expire. # This line makes reloading the page a sufficient action to keep the # session alive. request.session.modified = True user_profile = request.user # If a user hasn't signed the current Terms of Service, send them there if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \ int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version(): return accounts_accept_terms(request) narrow = [] # type: List[List[Text]] narrow_stream = None narrow_topic = request.GET.get("topic") if request.GET.get("stream"): try: narrow_stream_name = request.GET.get("stream") (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name( user_profile, narrow_stream_name) narrow = [["stream", narrow_stream.name]] except Exception: logging.exception("Narrow parsing") if narrow_stream is not None and narrow_topic is not None: narrow.append(["topic", narrow_topic]) register_ret = do_events_register(user_profile, request.client, apply_markdown=True, client_gravatar=True, narrow=narrow) user_has_messages = (register_ret['max_message_id'] != -1) # Reset our don't-spam-users-with-email counter since the # user has since logged in if user_profile.last_reminder is not None: user_profile.last_reminder = None user_profile.save(update_fields=["last_reminder"]) # Brand new users get narrowed to PM with welcome-bot needs_tutorial = user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING first_in_realm = realm_user_count(user_profile.realm) == 1 # If you are the only person in the realm and you didn't invite # anyone, we'll continue to encourage you to do so on the frontend. prompt_for_invites = first_in_realm and \ not PreregistrationUser.objects.filter(referred_by=user_profile).count() if user_profile.pointer == -1 and user_has_messages: # Put the new user's pointer at the bottom # # This improves performance, because we limit backfilling of messages # before the pointer. It's also likely that someone joining an # organization is interested in recent messages more than the very # first messages on the system. register_ret['pointer'] = register_ret['max_message_id'] user_profile.last_pointer_updater = request.session.session_key if user_profile.pointer == -1: latest_read = None else: try: latest_read = UserMessage.objects.get(user_profile=user_profile, message__id=user_profile.pointer) except UserMessage.DoesNotExist: # Don't completely fail if your saved pointer ID is invalid logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer)) latest_read = None # Set default language and make it persist default_language = register_ret['default_language'] url_lang = '/{}'.format(request.LANGUAGE_CODE) if not request.path.startswith(url_lang): translation.activate(default_language) request.session[translation.LANGUAGE_SESSION_KEY] = translation.get_language() # Pass parameters to the client-side JavaScript code. # These end up in a global JavaScript Object named 'page_params'. page_params = dict( # Server settings. development_environment = settings.DEVELOPMENT, debug_mode = settings.DEBUG, test_suite = settings.TEST_SUITE, poll_timeout = settings.POLL_TIMEOUT, login_page = settings.HOME_NOT_LOGGED_IN, root_domain_uri = settings.ROOT_DOMAIN_URI, maxfilesize = settings.MAX_FILE_UPLOAD_SIZE, max_avatar_file_size = settings.MAX_AVATAR_FILE_SIZE, server_generation = settings.SERVER_GENERATION, use_websockets = settings.USE_WEBSOCKETS, save_stacktraces = settings.SAVE_FRONTEND_STACKTRACES, server_inline_image_preview = settings.INLINE_IMAGE_PREVIEW, server_inline_url_embed_preview = settings.INLINE_URL_EMBED_PREVIEW, password_min_length = settings.PASSWORD_MIN_LENGTH, password_min_guesses = settings.PASSWORD_MIN_GUESSES, # Misc. extra data. have_initial_messages = user_has_messages, 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 = sent_time_in_epoch_seconds(latest_read), has_mobile_devices = num_push_devices_for_user(user_profile) > 0, bot_types = get_bot_types(), ) undesired_register_ret_fields = [ 'streams', ] for field_name in set(register_ret.keys()) - set(undesired_register_ret_fields): 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 = get_stream_recipient(narrow_stream.id) try: initial_pointer = Message.objects.filter(recipient=recipient).order_by('id').reverse()[0].id except IndexError: initial_pointer = -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"] = initial_pointer page_params["pointer"] = initial_pointer page_params["have_initial_messages"] = (initial_pointer != -1) page_params["enable_desktop_notifications"] = False statsd.incr('views.home') show_invites = True # Some realms only allow admins to invite users if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin: show_invites = False request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],) response = render(request, 'zerver/index.html', context={'user_profile': user_profile, 'page_params': JSONEncoderForHTML().encode(page_params), 'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")), 'avatar_url': avatar_url(user_profile), 'show_debug': settings.DEBUG and ('show_debug' in request.GET), 'pipeline': settings.PIPELINE_ENABLED, 'show_invites': show_invites, 'is_admin': user_profile.is_realm_admin, 'show_webathena': user_profile.realm.webathena_enabled, 'enable_feedback': settings.ENABLE_FEEDBACK, 'embedded': narrow_stream is not None, },) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) return response
def get_recipient_stream(r: Realm) -> Stream: return get_stream_recipient( Stream.objects.get(name='Verona', realm=r).id )
def test_import_realm(self) -> None: original_realm = Realm.objects.get(string_id='zulip') RealmEmoji.objects.get(realm=original_realm).delete() # data to test import of huddles huddle = [ self.example_email('hamlet'), self.example_email('othello') ] self.send_huddle_message( self.example_email('cordelia'), huddle, 'test huddle message' ) # data to test import of hotspots sample_user = self.example_user('hamlet') UserHotspot.objects.create( user=sample_user, hotspot='intro_streams' ) # data to test import of muted topic stream = get_stream(u'Verona', original_realm) add_topic_mute( user_profile=sample_user, stream_id=stream.id, recipient_id=get_stream_recipient(stream.id).id, topic_name=u'Verona2') # data to test import of botstoragedata and botconfigdata bot_profile = do_create_user( email="*****@*****.**", password="******", realm=original_realm, full_name="bot", short_name="bot", bot_type=UserProfile.EMBEDDED_BOT, bot_owner=sample_user) storage = StateHandler(bot_profile) storage.put('some key', 'some value') set_bot_config(bot_profile, 'entry 1', 'value 1') self._export_realm(original_realm) with patch('logging.info'): do_import_realm('var/test-export', 'test-zulip') # sanity checks # test realm self.assertTrue(Realm.objects.filter(string_id='test-zulip').exists()) imported_realm = Realm.objects.get(string_id='test-zulip') self.assertNotEqual(imported_realm.id, original_realm.id) def assert_realm_values(f: Callable[[Realm], Any], equal: bool=True) -> None: orig_realm_result = f(original_realm) imported_realm_result = f(imported_realm) # orig_realm_result should be truthy and have some values, otherwise # the test is kind of meaningless assert(orig_realm_result) if equal: self.assertEqual(orig_realm_result, imported_realm_result) else: self.assertNotEqual(orig_realm_result, imported_realm_result) # test users assert_realm_values( lambda r: {user.email for user in r.get_admin_users()} ) assert_realm_values( lambda r: {user.email for user in r.get_active_users()} ) # test stream assert_realm_values( lambda r: {stream.name for stream in get_active_streams(r)} ) # test recipients def get_recipient_stream(r: Realm) -> Stream: return get_stream_recipient( Stream.objects.get(name='Verona', realm=r).id ) def get_recipient_user(r: Realm) -> UserProfile: return get_personal_recipient( UserProfile.objects.get(full_name='Iago', realm=r).id ) assert_realm_values(lambda r: get_recipient_stream(r).type) assert_realm_values(lambda r: get_recipient_user(r).type) # test subscription def get_subscribers(recipient: Recipient) -> Set[str]: subscriptions = Subscription.objects.filter(recipient=recipient) users = {sub.user_profile.email for sub in subscriptions} return users assert_realm_values( lambda r: get_subscribers(get_recipient_stream(r)) ) assert_realm_values( lambda r: get_subscribers(get_recipient_user(r)) ) # test custom profile fields def get_custom_profile_field_names(r: Realm) -> Set[str]: custom_profile_fields = CustomProfileField.objects.filter(realm=r) custom_profile_field_names = {field.name for field in custom_profile_fields} return custom_profile_field_names assert_realm_values(get_custom_profile_field_names) def get_custom_profile_with_field_type_user(r: Realm) -> Tuple[Set[Any], Set[Any], Set[FrozenSet[str]]]: fields = CustomProfileField.objects.filter( field_type=CustomProfileField.USER, realm=r) def get_email(user_id: int) -> str: return UserProfile.objects.get(id=user_id).email def get_email_from_value(field_value: CustomProfileFieldValue) -> Set[str]: user_id_list = ujson.loads(field_value.value) return {get_email(user_id) for user_id in user_id_list} def custom_profile_field_values_for(fields: List[CustomProfileField]) -> Set[FrozenSet[str]]: user_emails = set() # type: Set[FrozenSet[str]] for field in fields: values = CustomProfileFieldValue.objects.filter(field=field) for value in values: user_emails.add(frozenset(get_email_from_value(value))) return user_emails field_names, field_hints = (set() for i in range(2)) for field in fields: field_names.add(field.name) field_hints.add(field.hint) return (field_hints, field_names, custom_profile_field_values_for(fields)) assert_realm_values(get_custom_profile_with_field_type_user) # test realmauditlog def get_realm_audit_log_event_type(r: Realm) -> Set[str]: realmauditlogs = RealmAuditLog.objects.filter(realm=r) realmauditlog_event_type = {log.event_type for log in realmauditlogs} return realmauditlog_event_type assert_realm_values(get_realm_audit_log_event_type) # test huddles def get_huddle_hashes(r: str) -> str: short_names = ['cordelia', 'hamlet', 'othello'] user_id_list = [UserProfile.objects.get(realm=r, short_name=name).id for name in short_names] huddle_hash = get_huddle_hash(user_id_list) return huddle_hash assert_realm_values(get_huddle_hashes, equal=False) def get_huddle_message(r: str) -> str: huddle_hash = get_huddle_hashes(r) huddle_id = Huddle.objects.get(huddle_hash=huddle_hash).id huddle_recipient = Recipient.objects.get(type_id=huddle_id, type=3) huddle_message = Message.objects.get(recipient=huddle_recipient) return huddle_message.content assert_realm_values(get_huddle_message) self.assertEqual(get_huddle_message(imported_realm), 'test huddle message') # test userhotspot def get_user_hotspots(r: str) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') hotspots = UserHotspot.objects.filter(user=user_profile) user_hotspots = {hotspot.hotspot for hotspot in hotspots} return user_hotspots assert_realm_values(get_user_hotspots) # test muted topics def get_muted_topics(r: Realm) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') muted_topics = MutedTopic.objects.filter(user_profile=user_profile) topic_names = {muted_topic.topic_name for muted_topic in muted_topics} return topic_names assert_realm_values(get_muted_topics) # test usergroups assert_realm_values( lambda r: {group.name for group in UserGroup.objects.filter(realm=r)} ) def get_user_membership(r: str) -> Set[str]: usergroup = UserGroup.objects.get(realm=r, name='hamletcharacters') usergroup_membership = UserGroupMembership.objects.filter(user_group=usergroup) users = {membership.user_profile.email for membership in usergroup_membership} return users assert_realm_values(get_user_membership) # test botstoragedata and botconfigdata def get_botstoragedata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_storage_data = BotStorageData.objects.get(bot_profile=bot_profile) return {'key': bot_storage_data.key, 'data': bot_storage_data.value} assert_realm_values(get_botstoragedata) def get_botconfigdata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_config_data = BotConfigData.objects.get(bot_profile=bot_profile) return {'key': bot_config_data.key, 'data': bot_config_data.value} assert_realm_values(get_botconfigdata) # test messages def get_stream_messages(r: Realm) -> Message: recipient = get_recipient_stream(r) messages = Message.objects.filter(recipient=recipient) return messages def get_stream_topics(r: Realm) -> Set[str]: messages = get_stream_messages(r) topics = {m.topic_name() for m in messages} return topics assert_realm_values(get_stream_topics) # test usermessages def get_usermessages_user(r: Realm) -> Set[Any]: messages = get_stream_messages(r).order_by('content') usermessage = UserMessage.objects.filter(message=messages[0]) usermessage_user = {um.user_profile.email for um in usermessage} return usermessage_user assert_realm_values(get_usermessages_user)
def test_stream_recipient_info(self) -> None: hamlet = self.example_user('hamlet') cordelia = self.example_user('cordelia') othello = self.example_user('othello') realm = hamlet.realm stream_name = 'Test Stream' topic_name = 'test topic' for user in [hamlet, cordelia, othello]: self.subscribe(user, stream_name) stream = get_stream(stream_name, realm) recipient = get_stream_recipient(stream.id) stream_topic = StreamTopicTarget( stream_id=stream.id, topic_name=topic_name, ) sub = get_subscription(stream_name, hamlet) sub.push_notifications = True sub.save() info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, ) all_user_ids = {hamlet.id, cordelia.id, othello.id} expected_info = dict( active_user_ids=all_user_ids, push_notify_user_ids=set(), stream_push_user_ids={hamlet.id}, stream_email_user_ids=set(), um_eligible_user_ids=all_user_ids, long_term_idle_user_ids=set(), default_bot_user_ids=set(), service_bot_tuples=[], ) self.assertEqual(info, expected_info) # Now mute Hamlet to omit him from stream_push_user_ids. add_topic_mute( user_profile=hamlet, stream_id=stream.id, recipient_id=recipient.id, topic_name=topic_name, ) info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, ) self.assertEqual(info['stream_push_user_ids'], set()) # Add a service bot. service_bot = do_create_user( email='*****@*****.**', password='', realm=realm, full_name='', short_name='', bot_type=UserProfile.EMBEDDED_BOT, ) info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, possibly_mentioned_user_ids={service_bot.id} ) self.assertEqual(info['service_bot_tuples'], [ (service_bot.id, UserProfile.EMBEDDED_BOT), ]) # Add a normal bot. normal_bot = do_create_user( email='*****@*****.**', password='', realm=realm, full_name='', short_name='', bot_type=UserProfile.DEFAULT_BOT, ) info = get_recipient_info( recipient=recipient, sender_id=hamlet.id, stream_topic=stream_topic, possibly_mentioned_user_ids={service_bot.id, normal_bot.id} ) self.assertEqual(info['default_bot_user_ids'], {normal_bot.id})
def test_import_realm(self) -> None: original_realm = Realm.objects.get(string_id='zulip') RealmEmoji.objects.get(realm=original_realm).delete() # data to test import of huddles huddle = [self.example_email('hamlet'), self.example_email('othello')] self.send_huddle_message(self.example_email('cordelia'), huddle, 'test huddle message') user_mention_message = '@**King Hamlet** Hello' self.send_stream_message(self.example_email("iago"), "Verona", user_mention_message) stream_mention_message = 'Subscribe to #**Denmark**' self.send_stream_message(self.example_email("hamlet"), "Verona", stream_mention_message) user_group_mention_message = 'Hello @*hamletcharacters*' self.send_stream_message(self.example_email("othello"), "Verona", user_group_mention_message) special_characters_message = "```\n'\n```\n@**Polonius**" self.send_stream_message(self.example_email("iago"), "Denmark", special_characters_message) # data to test import of hotspots sample_user = self.example_user('hamlet') UserHotspot.objects.create(user=sample_user, hotspot='intro_streams') # data to test import of muted topic stream = get_stream(u'Verona', original_realm) add_topic_mute(user_profile=sample_user, stream_id=stream.id, recipient_id=get_stream_recipient(stream.id).id, topic_name=u'Verona2') # data to test import of botstoragedata and botconfigdata bot_profile = do_create_user(email="*****@*****.**", password="******", realm=original_realm, full_name="bot", short_name="bot", bot_type=UserProfile.EMBEDDED_BOT, bot_owner=sample_user) storage = StateHandler(bot_profile) storage.put('some key', 'some value') set_bot_config(bot_profile, 'entry 1', 'value 1') self._export_realm(original_realm) with patch('logging.info'): with self.settings(BILLING_ENABLED=False): do_import_realm( os.path.join(settings.TEST_WORKER_DIR, 'test-export'), 'test-zulip') # sanity checks # test realm self.assertTrue(Realm.objects.filter(string_id='test-zulip').exists()) imported_realm = Realm.objects.get(string_id='test-zulip') self.assertNotEqual(imported_realm.id, original_realm.id) def assert_realm_values(f: Callable[[Realm], Any], equal: bool = True) -> None: orig_realm_result = f(original_realm) imported_realm_result = f(imported_realm) # orig_realm_result should be truthy and have some values, otherwise # the test is kind of meaningless assert (orig_realm_result) if equal: self.assertEqual(orig_realm_result, imported_realm_result) else: self.assertNotEqual(orig_realm_result, imported_realm_result) # test users assert_realm_values( lambda r: {user.email for user in r.get_admin_users_and_bots()}) assert_realm_values( lambda r: {user.email for user in r.get_active_users()}) # test stream assert_realm_values( lambda r: {stream.name for stream in get_active_streams(r)}) # test recipients def get_recipient_stream(r: Realm) -> Stream: return get_stream_recipient( Stream.objects.get(name='Verona', realm=r).id) def get_recipient_user(r: Realm) -> UserProfile: return get_personal_recipient( UserProfile.objects.get(full_name='Iago', realm=r).id) assert_realm_values(lambda r: get_recipient_stream(r).type) assert_realm_values(lambda r: get_recipient_user(r).type) # test subscription def get_subscribers(recipient: Recipient) -> Set[str]: subscriptions = Subscription.objects.filter(recipient=recipient) users = {sub.user_profile.email for sub in subscriptions} return users assert_realm_values(lambda r: get_subscribers(get_recipient_stream(r))) assert_realm_values(lambda r: get_subscribers(get_recipient_user(r))) # test custom profile fields def get_custom_profile_field_names(r: Realm) -> Set[str]: custom_profile_fields = CustomProfileField.objects.filter(realm=r) custom_profile_field_names = { field.name for field in custom_profile_fields } return custom_profile_field_names assert_realm_values(get_custom_profile_field_names) def get_custom_profile_with_field_type_user( r: Realm) -> Tuple[Set[Any], Set[Any], Set[FrozenSet[str]]]: fields = CustomProfileField.objects.filter( field_type=CustomProfileField.USER, realm=r) def get_email(user_id: int) -> str: return UserProfile.objects.get(id=user_id).email def get_email_from_value( field_value: CustomProfileFieldValue) -> Set[str]: user_id_list = ujson.loads(field_value.value) return {get_email(user_id) for user_id in user_id_list} def custom_profile_field_values_for( fields: List[CustomProfileField]) -> Set[FrozenSet[str]]: user_emails = set() # type: Set[FrozenSet[str]] for field in fields: values = CustomProfileFieldValue.objects.filter( field=field) for value in values: user_emails.add(frozenset(get_email_from_value(value))) return user_emails field_names, field_hints = (set() for i in range(2)) for field in fields: field_names.add(field.name) field_hints.add(field.hint) return (field_hints, field_names, custom_profile_field_values_for(fields)) assert_realm_values(get_custom_profile_with_field_type_user) # test realmauditlog def get_realm_audit_log_event_type(r: Realm) -> Set[str]: realmauditlogs = RealmAuditLog.objects.filter(realm=r).exclude( event_type=RealmAuditLog.REALM_PLAN_TYPE_CHANGED) realmauditlog_event_type = { log.event_type for log in realmauditlogs } return realmauditlog_event_type assert_realm_values(get_realm_audit_log_event_type) # test huddles def get_huddle_hashes(r: str) -> str: short_names = ['cordelia', 'hamlet', 'othello'] user_id_list = [ UserProfile.objects.get(realm=r, short_name=name).id for name in short_names ] huddle_hash = get_huddle_hash(user_id_list) return huddle_hash assert_realm_values(get_huddle_hashes, equal=False) def get_huddle_message(r: str) -> str: huddle_hash = get_huddle_hashes(r) huddle_id = Huddle.objects.get(huddle_hash=huddle_hash).id huddle_recipient = Recipient.objects.get(type_id=huddle_id, type=3) huddle_message = Message.objects.get(recipient=huddle_recipient) return huddle_message.content assert_realm_values(get_huddle_message) self.assertEqual(get_huddle_message(imported_realm), 'test huddle message') # test userhotspot def get_user_hotspots(r: str) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') hotspots = UserHotspot.objects.filter(user=user_profile) user_hotspots = {hotspot.hotspot for hotspot in hotspots} return user_hotspots assert_realm_values(get_user_hotspots) # test muted topics def get_muted_topics(r: Realm) -> Set[str]: user_profile = UserProfile.objects.get(realm=r, short_name='hamlet') muted_topics = MutedTopic.objects.filter(user_profile=user_profile) topic_names = { muted_topic.topic_name for muted_topic in muted_topics } return topic_names assert_realm_values(get_muted_topics) # test usergroups assert_realm_values( lambda r: {group.name for group in UserGroup.objects.filter(realm=r)}) def get_user_membership(r: str) -> Set[str]: usergroup = UserGroup.objects.get(realm=r, name='hamletcharacters') usergroup_membership = UserGroupMembership.objects.filter( user_group=usergroup) users = { membership.user_profile.email for membership in usergroup_membership } return users assert_realm_values(get_user_membership) # test botstoragedata and botconfigdata def get_botstoragedata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_storage_data = BotStorageData.objects.get( bot_profile=bot_profile) return { 'key': bot_storage_data.key, 'data': bot_storage_data.value } assert_realm_values(get_botstoragedata) def get_botconfigdata(r: Realm) -> Dict[str, Any]: bot_profile = UserProfile.objects.get(full_name="bot", realm=r) bot_config_data = BotConfigData.objects.get( bot_profile=bot_profile) return {'key': bot_config_data.key, 'data': bot_config_data.value} assert_realm_values(get_botconfigdata) # test messages def get_stream_messages(r: Realm) -> Message: recipient = get_recipient_stream(r) messages = Message.objects.filter(recipient=recipient) return messages def get_stream_topics(r: Realm) -> Set[str]: messages = get_stream_messages(r) topics = {m.topic_name() for m in messages} return topics assert_realm_values(get_stream_topics) # test usermessages def get_usermessages_user(r: Realm) -> Set[Any]: messages = get_stream_messages(r).order_by('content') usermessage = UserMessage.objects.filter(message=messages[0]) usermessage_user = {um.user_profile.email for um in usermessage} return usermessage_user assert_realm_values(get_usermessages_user) # tests to make sure that various data-*-ids in rendered_content # are replaced correctly with the values of newer realm. def get_user_mention(r: Realm) -> Set[Any]: mentioned_user = UserProfile.objects.get( delivery_email=self.example_email("hamlet"), realm=r) data_user_id = 'data-user-id="{}"'.format(mentioned_user.id) mention_message = get_stream_messages(r).get( rendered_content__contains=data_user_id) return mention_message.content assert_realm_values(get_user_mention) def get_stream_mention(r: Realm) -> Set[Any]: mentioned_stream = get_stream(u'Denmark', r) data_stream_id = 'data-stream-id="{}"'.format(mentioned_stream.id) mention_message = get_stream_messages(r).get( rendered_content__contains=data_stream_id) return mention_message.content assert_realm_values(get_stream_mention) def get_user_group_mention(r: Realm) -> Set[Any]: user_group = UserGroup.objects.get(realm=r, name='hamletcharacters') data_usergroup_id = 'data-user-group-id="{}"'.format(user_group.id) mention_message = get_stream_messages(r).get( rendered_content__contains=data_usergroup_id) return mention_message.content assert_realm_values(get_user_group_mention) # test to highlight that bs4 which we use to do data-**id # replacements modifies the HTML sometimes. eg replacing <br> # with </br>, ' with \' etc. The modifications doesn't # affect how the browser displays the rendered_content so we # are okay with using bs4 for this. lxml package also has # similar behavior. orig_polonius_user = UserProfile.objects.get( email=self.example_email("polonius"), realm=original_realm) original_msg = Message.objects.get(content=special_characters_message, sender__realm=original_realm) self.assertEqual(original_msg.rendered_content, ( '<div class="codehilite"><pre><span></span>'\n</pre></div>\n\n\n' '<p><span class="user-mention" data-user-id="%s">@Polonius</span></p>' % (orig_polonius_user.id, ))) imported_polonius_user = UserProfile.objects.get( email=self.example_email("polonius"), realm=imported_realm) imported_msg = Message.objects.get(content=special_characters_message, sender__realm=imported_realm) self.assertEqual(imported_msg.rendered_content, ( '<div class="codehilite"><pre><span></span>\'\n</pre></div>\n' '<p><span class="user-mention" data-user-id="%s">@Polonius</span></p>' % (imported_polonius_user.id, ))) # Check recipient_id was generated correctly for the imported users and streams. for user_profile in UserProfile.objects.filter(realm=imported_realm): self.assertEqual(user_profile.recipient_id, get_personal_recipient(user_profile.id).id) for stream in Stream.objects.filter(realm=imported_realm): self.assertEqual(stream.recipient_id, get_stream_recipient(stream.id).id)