Add is_zephyr to the Stream model.

Add this field to the Stream model will prevent us from having
to look at realm data for several types of stream operations, which
can be prone to either doing extra database lookups or making
our cached data bloated.

Going forward, we'll set stream.is_zephyr to True whenever the
realm's string id is "zephyr".
This commit is contained in:
Steve Howell
2017-10-08 12:16:51 -07:00
committed by Tim Abbott
parent c1f12e3f8a
commit a6ad9a6d7c
6 changed files with 72 additions and 12 deletions

View File

@@ -1307,10 +1307,16 @@ def send_stream_creation_event(stream, user_ids):
def create_stream_if_needed(realm, stream_name, invite_only=False, stream_description = ""):
# type: (Realm, Text, bool, Text) -> Tuple[Stream, bool]
(stream, created) = Stream.objects.get_or_create(
realm=realm, name__iexact=stream_name,
defaults={'name': stream_name,
'description': stream_description,
'invite_only': invite_only})
realm=realm,
name__iexact=stream_name,
defaults = dict(
name=stream_name,
description=stream_description,
invite_only=invite_only,
is_in_zephyr_realm=realm.is_zephyr_mirror_realm
)
)
if created:
Recipient.objects.create(type_id=stream.id, type=Recipient.STREAM)
if stream.is_public():
@@ -2069,7 +2075,7 @@ def bulk_add_subscriptions(streams, users, from_stream_creation=False, acting_us
def fetch_stream_subscriber_user_ids(stream):
# type: (Stream) -> List[int]
if stream.realm.is_zephyr_mirror_realm and not stream.invite_only:
if stream.is_in_zephyr_realm and not stream.invite_only:
return []
user_ids = all_subscribers_by_stream[stream.id]
return user_ids
@@ -2104,7 +2110,7 @@ def bulk_add_subscriptions(streams, users, from_stream_creation=False, acting_us
# subscribers lists of streams in their browser; everyone for
# public streams and only existing subscribers for private streams.
for stream in streams:
if stream.realm.is_zephyr_mirror_realm and not stream.invite_only:
if stream.is_in_zephyr_realm and not stream.invite_only:
continue
new_user_ids = [user.id for user in users if (user.id, stream.id) in new_streams]
@@ -2217,7 +2223,7 @@ def bulk_remove_subscriptions(users, streams, acting_user=None):
all_subscribers_by_stream = get_user_ids_for_streams(streams=streams)
for stream in streams:
if stream.realm.is_zephyr_mirror_realm and not stream.invite_only:
if stream.is_in_zephyr_realm and not stream.invite_only:
continue
altered_users = altered_user_dict[stream.id]

View File

@@ -64,7 +64,8 @@ def bulk_create_streams(realm, stream_dict):
streams_to_create.append(
Stream(
realm=realm, name=name, description=options["description"],
invite_only=options["invite_only"]
invite_only=options["invite_only"],
is_in_zephyr_realm=realm.is_zephyr_mirror_realm,
)
)
# Sort streams by name before creating them so that we can have a

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.5 on 2017-10-08 18:37
from __future__ import unicode_literals
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps
from django.db import connection, migrations, models
def populate_is_zephyr(apps, schema_editor):
# type: (StateApps, DatabaseSchemaEditor) -> None
Realm = apps.get_model("zerver", "Realm")
Stream = apps.get_model("zerver", "Stream")
realms = Realm.objects.filter(
string_id='zephyr',
)
for realm in realms:
Stream.objects.filter(
realm_id=realm.id
).update(
is_in_zephyr_realm=True
)
class Migration(migrations.Migration):
dependencies = [
('zerver', '0109_mark_tutorial_status_finished'),
]
operations = [
migrations.AddField(
model_name='stream',
name='is_in_zephyr_realm',
field=models.BooleanField(default=False),
),
migrations.RunPython(populate_is_zephyr,
reverse_code=migrations.RunPython.noop),
]

View File

@@ -842,6 +842,17 @@ class Stream(ModelReprMixin, models.Model):
name = models.CharField(max_length=MAX_NAME_LENGTH, db_index=True) # type: Text
realm = models.ForeignKey(Realm, db_index=True, on_delete=CASCADE) # type: Realm
invite_only = models.NullBooleanField(default=False) # type: Optional[bool]
# The unique thing about Zephyr public streams is that we never list their
# users. We may try to generalize this concept later, but for now
# we just use a concrete field. (Zephyr public streams aren't exactly like
# invite-only streams--while both are private in terms of listing users,
# for Zephyr we don't even list users to stream members, yet membership
# is more public in the sense that you don't need a Zulip invite to join.
# This field is populated directly from UserProfile.is_zephyr_mirror_realm,
# and the reason for denormalizing field is performance.
is_in_zephyr_realm = models.BooleanField(default=False) # type: bool
# Used by the e-mail forwarder. The e-mail RFC specifies a maximum
# e-mail length of 254, and our max stream length is 30, so we
# have plenty of room for the token.
@@ -859,7 +870,7 @@ class Stream(ModelReprMixin, models.Model):
def is_public(self):
# type: () -> bool
# All streams are private in Zephyr mirroring realms.
return not self.invite_only and not self.realm.is_zephyr_mirror_realm
return not self.invite_only and not self.is_in_zephyr_realm
class Meta(object):
unique_together = ("name", "realm")

View File

@@ -608,7 +608,8 @@ class GetOldMessagesTest(ZulipTestCase):
# it to ensure that we actually have a stream message in this
# narrow view.
lambda_stream_name = u"\u03bb-stream"
self.subscribe(self.mit_user("starnine"), lambda_stream_name)
stream = self.subscribe(self.mit_user("starnine"), lambda_stream_name)
self.assertTrue(stream.is_in_zephyr_realm)
lambda_stream_d_name = u"\u03bb-stream.d"
self.subscribe(self.mit_user("starnine"), lambda_stream_d_name)

View File

@@ -156,7 +156,8 @@ class StreamAdminTest(ZulipTestCase):
result = self.client_patch("/json/streams/%d" % (stream_id,), params)
self.assert_json_error(result, 'Invalid stream id')
self.subscribe(user_profile, 'private_stream')
stream = self.subscribe(user_profile, 'private_stream')
self.assertFalse(stream.is_in_zephyr_realm)
do_change_is_admin(user_profile, True)
params = {
@@ -2570,7 +2571,8 @@ class GetSubscribersTest(ZulipTestCase):
email = mit_user_profile.email
users_to_subscribe = [email, self.mit_email("espuser")]
for email in users_to_subscribe:
self.subscribe(get_user(email, mit_user_profile.realm), "mit_stream")
stream = self.subscribe(get_user(email, mit_user_profile.realm), "mit_stream")
self.assertTrue(stream.is_in_zephyr_realm)
ret = self.common_subscribe_to_streams(
email,