def create_stream_if_needed( realm: Realm, stream_name: str, *, invite_only: bool = False, is_web_public: bool = False, stream_post_policy: int = Stream.STREAM_POST_POLICY_EVERYONE, history_public_to_subscribers: Optional[bool] = None, stream_description: str = "", message_retention_days: Optional[int] = None, acting_user: Optional[UserProfile] = None) -> Tuple[Stream, bool]: history_public_to_subscribers = get_default_value_for_history_public_to_subscribers( realm, invite_only, history_public_to_subscribers) (stream, created) = Stream.objects.get_or_create( realm=realm, name__iexact=stream_name, defaults=dict( name=stream_name, description=stream_description, invite_only=invite_only, is_web_public=is_web_public, stream_post_policy=stream_post_policy, history_public_to_subscribers=history_public_to_subscribers, is_in_zephyr_realm=realm.is_zephyr_mirror_realm, message_retention_days=message_retention_days, ), ) if created: recipient = Recipient.objects.create(type_id=stream.id, type=Recipient.STREAM) stream.recipient = recipient stream.rendered_description = render_stream_description( stream_description) stream.save(update_fields=["recipient", "rendered_description"]) if stream.is_public(): send_stream_creation_event( stream, active_non_guest_user_ids(stream.realm_id)) else: realm_admin_ids = [ user.id for user in stream.realm.get_admin_users_and_bots() ] send_stream_creation_event(stream, realm_admin_ids) event_time = timezone_now() RealmAuditLog.objects.create(realm=realm, acting_user=acting_user, modified_stream=stream, event_type=RealmAuditLog.STREAM_CREATED, event_time=event_time) return stream, created
def bulk_get_subscriber_peer_info( realm: Realm, streams: List[Stream], ) -> SubscriberPeerInfo: """ Glossary: subscribed_ids: This shows the users who are actually subscribed to the stream, which we generally send to the person subscribing to the stream. peer_ids: These are the folks that need to know about a new subscriber. It's usually a superset of the subscribers. """ subscribed_ids = {} peer_ids = {} private_stream_ids = {stream.id for stream in streams if stream.invite_only} public_stream_ids = {stream.id for stream in streams if not stream.invite_only} stream_user_ids = get_user_ids_for_streams(private_stream_ids | public_stream_ids) if private_stream_ids: realm_admin_ids = {user.id for user in realm.get_admin_users_and_bots()} for stream_id in private_stream_ids: subscribed_user_ids = stream_user_ids.get(stream_id, set()) subscribed_ids[stream_id] = subscribed_user_ids peer_ids[stream_id] = subscribed_user_ids | realm_admin_ids if public_stream_ids: non_guests = active_non_guest_user_ids(realm.id) for stream_id in public_stream_ids: subscribed_user_ids = stream_user_ids.get(stream_id, set()) subscribed_ids[stream_id] = subscribed_user_ids peer_ids[stream_id] = set(non_guests) return SubscriberPeerInfo( subscribed_ids=subscribed_ids, peer_ids=peer_ids, )
def create_stream_if_needed( realm: Realm, stream_name: str, *, invite_only: bool = False, stream_post_policy: int = Stream.STREAM_POST_POLICY_EVERYONE, history_public_to_subscribers: Optional[bool] = None, stream_description: str = "") -> Tuple[Stream, bool]: history_public_to_subscribers = get_default_value_for_history_public_to_subscribers( realm, invite_only, history_public_to_subscribers) (stream, created) = Stream.objects.get_or_create( realm=realm, name__iexact=stream_name, defaults=dict( name=stream_name, description=stream_description, invite_only=invite_only, stream_post_policy=stream_post_policy, history_public_to_subscribers=history_public_to_subscribers, is_in_zephyr_realm=realm.is_zephyr_mirror_realm, ), ) if created: recipient = Recipient.objects.create(type_id=stream.id, type=Recipient.STREAM) stream.recipient = recipient stream.rendered_description = render_stream_description( stream_description) stream.save(update_fields=["recipient", "rendered_description"]) if stream.is_public(): send_stream_creation_event( stream, active_non_guest_user_ids(stream.realm_id)) else: realm_admin_ids = [ user.id for user in stream.realm.get_admin_users_and_bots() ] send_stream_creation_event(stream, realm_admin_ids) return stream, created
def bulk_get_peers( realm: Realm, streams: List[Stream], ) -> Dict[int, Set[int]]: # This is almost a subset of bulk_get_subscriber_peer_info, # with the nuance that we don't have to query subscribers # for public streams. (The other functions tries to save # a query hop.) peer_ids = {} private_stream_ids = { stream.id for stream in streams if stream.invite_only } public_stream_ids = { stream.id for stream in streams if not stream.invite_only } if private_stream_ids: realm_admin_ids = { user.id for user in realm.get_admin_users_and_bots() } stream_user_ids = get_user_ids_for_streams(private_stream_ids) for stream_id in private_stream_ids: subscribed_user_ids = stream_user_ids.get(stream_id, set()) peer_ids[stream_id] = subscribed_user_ids | realm_admin_ids if public_stream_ids: non_guests = active_non_guest_user_ids(realm.id) for stream_id in public_stream_ids: peer_ids[stream_id] = set(non_guests) return peer_ids
def send_peer_subscriber_events( op: str, realm: Realm, stream_dict: Dict[int, Stream], altered_user_dict: Dict[int, Set[int]], private_peer_dict: Dict[int, Set[int]], ) -> None: # Send peer_add/peer_remove events to other users who are tracking the # subscribers lists of streams in their browser; everyone for # public streams and only existing subscribers for private streams. assert op in ["peer_add", "peer_remove"] private_stream_ids = [ stream_id for stream_id in altered_user_dict if stream_dict[stream_id].invite_only ] for stream_id in private_stream_ids: altered_user_ids = altered_user_dict[stream_id] peer_user_ids = private_peer_dict[stream_id] - altered_user_ids if peer_user_ids and altered_user_ids: event = dict( type="subscription", op=op, stream_ids=[stream_id], user_ids=sorted(list(altered_user_ids)), ) send_event(realm, event, peer_user_ids) public_stream_ids = [ stream_id for stream_id in altered_user_dict if not stream_dict[stream_id].invite_only and not stream_dict[stream_id].is_in_zephyr_realm ] if public_stream_ids: user_streams: Dict[int, Set[int]] = defaultdict(set) public_peer_ids = set(active_non_guest_user_ids(realm.id)) for stream_id in public_stream_ids: altered_user_ids = altered_user_dict[stream_id] peer_user_ids = public_peer_ids - altered_user_ids if peer_user_ids and altered_user_ids: if len(altered_user_ids) == 1: # If we only have one user, we will try to # find other streams they have (un)subscribed to # (where it's just them). This optimization # typically works when a single user is subscribed # to multiple default public streams during # new-user registration. # # This optimization depends on all public streams # having the same peers for any single user, which # isn't the case for private streams. altered_user_id = list(altered_user_ids)[0] user_streams[altered_user_id].add(stream_id) else: event = dict( type="subscription", op=op, stream_ids=[stream_id], user_ids=sorted(list(altered_user_ids)), ) send_event(realm, event, peer_user_ids) for user_id, stream_ids in user_streams.items(): peer_user_ids = public_peer_ids - {user_id} event = dict( type="subscription", op=op, stream_ids=sorted(list(stream_ids)), user_ids=[user_id], ) send_event(realm, event, peer_user_ids)
def notify_default_streams(realm: Realm) -> None: event = dict( type="default_streams", default_streams=streams_to_dicts_sorted(get_default_streams_for_realm(realm.id)), ) transaction.on_commit(lambda: send_event(realm, event, active_non_guest_user_ids(realm.id)))