def notify_realm_custom_profile_fields(realm: Realm) -> None: fields = custom_profile_fields_for_realm(realm.id) event = dict(type="custom_profile_fields", fields=[f.as_dict() for f in fields]) send_event(realm, event, active_user_ids(realm.id))
def send_stream_creation_event(stream: Stream, user_ids: List[int]) -> None: event = dict(type="stream", op="create", streams=[stream.to_dict()]) send_event(stream.realm, event, user_ids)
def do_change_bot_owner(user_profile: UserProfile, bot_owner: UserProfile, acting_user: UserProfile) -> None: previous_owner = user_profile.bot_owner user_profile.bot_owner = bot_owner user_profile.save( ) # Can't use update_fields because of how the foreign key works. event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, acting_user=acting_user, modified_user=user_profile, event_type=RealmAuditLog.USER_BOT_OWNER_CHANGED, event_time=event_time, ) update_users = bot_owner_user_ids(user_profile) # For admins, update event is sent instead of delete/add # event. bot_data of admin contains all the # bots and none of them should be removed/(added again). # Delete the bot from previous owner's bot data. if previous_owner and not previous_owner.is_realm_admin: delete_event = dict( type="realm_bot", op="delete", bot=dict(user_id=user_profile.id, ), ) transaction.on_commit(lambda: send_event( user_profile.realm, delete_event, {previous_owner.id}, )) # Do not send update event for previous bot owner. update_users = update_users - {previous_owner.id} # Notify the new owner that the bot has been added. if not bot_owner.is_realm_admin: add_event = created_bot_event(user_profile) transaction.on_commit( lambda: send_event(user_profile.realm, add_event, {bot_owner.id})) # Do not send update event for bot_owner. update_users = update_users - {bot_owner.id} bot_event = dict( type="realm_bot", op="update", bot=dict( user_id=user_profile.id, owner_id=user_profile.bot_owner.id, ), ) transaction.on_commit(lambda: send_event( user_profile.realm, bot_event, update_users, )) # Since `bot_owner_id` is included in the user profile dict we need # to update the users dict with the new bot owner id event = dict( type="realm_user", op="update", person=dict( user_id=user_profile.id, bot_owner_id=user_profile.bot_owner.id, ), ) transaction.on_commit(lambda: send_event( user_profile.realm, event, active_user_ids(user_profile.realm_id)))
def do_update_message_flags(user_profile: UserProfile, operation: str, flag: str, messages: List[int]) -> Tuple[int, List[int]]: valid_flags = [ item for item in UserMessage.flags if item not in UserMessage.NON_API_FLAGS ] if flag not in valid_flags: raise JsonableError(_("Invalid flag: '{}'").format(flag)) if flag in UserMessage.NON_EDITABLE_FLAGS: raise JsonableError(_("Flag not editable: '{}'").format(flag)) if operation not in ("add", "remove"): raise JsonableError( _("Invalid message flag operation: '{}'").format(operation)) flagattr = getattr(UserMessage.flags, flag) msgs = UserMessage.objects.filter(user_profile=user_profile, message_id__in=messages) um_message_ids = {um.message_id for um in msgs} historical_message_ids = list(set(messages) - um_message_ids) # Users can mutate flags for messages that don't have a UserMessage yet. # First, validate that the user is even allowed to access these message_ids. for message_id in historical_message_ids: access_message(user_profile, message_id) # And then create historical UserMessage records. See the called function for more context. create_historical_user_messages(user_id=user_profile.id, message_ids=historical_message_ids) with transaction.atomic(): if operation == "add": msgs = (msgs.select_for_update().order_by("message_id").extra( where=[UserMessage.where_flag_is_absent(flagattr)])) updated_message_ids = [um.message_id for um in msgs] msgs.filter(message_id__in=updated_message_ids).update( flags=F("flags").bitor(flagattr)) elif operation == "remove": msgs = (msgs.select_for_update().order_by("message_id").extra( where=[UserMessage.where_flag_is_present(flagattr)])) updated_message_ids = [um.message_id for um in msgs] msgs.filter(message_id__in=updated_message_ids).update( flags=F("flags").bitand(~flagattr)) count = len(updated_message_ids) event = { "type": "update_message_flags", "op": operation, "operation": operation, "flag": flag, "messages": updated_message_ids, "all": False, } if flag == "read" and operation == "remove": # When removing the read flag (i.e. marking messages as # unread), extend the event with an additional object with # details on the messages required to update the client's # `unread_msgs` data structure. raw_unread_data = get_raw_unread_data(user_profile, updated_message_ids) event["message_details"] = format_unread_message_details( user_profile.id, raw_unread_data) send_event(user_profile.realm, event, [user_profile.id]) if flag == "read" and operation == "add": event_time = timezone_now() do_clear_mobile_push_notifications_for_ids([user_profile.id], updated_message_ids) do_increment_logging_stat(user_profile, COUNT_STATS["messages_read::hour"], None, event_time, increment=count) do_increment_logging_stat( user_profile, COUNT_STATS["messages_read_interactions::hour"], None, event_time, increment=min(1, count), ) return count, updated_message_ids
def do_send_delete_user_group_event(realm: Realm, user_group_id: int, realm_id: int) -> None: event = dict(type="user_group", op="remove", group_id=user_group_id) send_event(realm, event, active_user_ids(realm_id))
def do_deactivate_user( user_profile: UserProfile, _cascade: bool = True, *, acting_user: Optional[UserProfile] ) -> None: if not user_profile.is_active: return if _cascade: # We need to deactivate bots before the target user, to ensure # that a failure partway through this function cannot result # in only the user being deactivated. bot_profiles = get_active_bots_owned_by_user(user_profile) for profile in bot_profiles: do_deactivate_user(profile, _cascade=False, acting_user=acting_user) with transaction.atomic(): if user_profile.realm.is_zephyr_mirror_realm: # nocoverage # For zephyr mirror users, we need to make them a mirror dummy # again; otherwise, other users won't get the correct behavior # when trying to send messages to this person inside Zulip. # # Ideally, we need to also ensure their zephyr mirroring bot # isn't running, but that's a separate issue. user_profile.is_mirror_dummy = True user_profile.save(update_fields=["is_mirror_dummy"]) change_user_is_active(user_profile, False) clear_scheduled_emails(user_profile.id) revoke_invites_generated_by_user(user_profile) event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, modified_user=user_profile, acting_user=acting_user, event_type=RealmAuditLog.USER_DEACTIVATED, event_time=event_time, extra_data=orjson.dumps( { RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm), } ).decode(), ) do_increment_logging_stat( user_profile.realm, COUNT_STATS["active_users_log:is_bot:day"], user_profile.is_bot, event_time, increment=-1, ) if settings.BILLING_ENABLED: update_license_ledger_if_needed(user_profile.realm, event_time) delete_user_sessions(user_profile) event = dict( type="realm_user", op="remove", person=dict(user_id=user_profile.id, full_name=user_profile.full_name), ) send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) if user_profile.is_bot: event = dict( type="realm_bot", op="remove", bot=dict(user_id=user_profile.id, full_name=user_profile.full_name), ) send_event(user_profile.realm, event, bot_owner_user_ids(user_profile))
def notify_alert_words(user_profile: UserProfile, words: Sequence[str]) -> None: event = dict(type="alert_words", alert_words=words) send_event(user_profile.realm, event, [user_profile.id])