def do_change_default_all_public_streams( user_profile: UserProfile, value: bool, *, acting_user: Optional[UserProfile]) -> None: old_value = user_profile.default_all_public_streams user_profile.default_all_public_streams = value user_profile.save(update_fields=["default_all_public_streams"]) event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, event_type=RealmAuditLog.USER_DEFAULT_ALL_PUBLIC_STREAMS_CHANGED, event_time=event_time, modified_user=user_profile, acting_user=acting_user, extra_data=orjson.dumps({ RealmAuditLog.OLD_VALUE: old_value, RealmAuditLog.NEW_VALUE: value, }).decode(), ) if user_profile.is_bot: event = dict( type="realm_bot", op="update", bot=dict( user_id=user_profile.id, default_all_public_streams=user_profile. default_all_public_streams, ), ) transaction.on_commit(lambda: send_event( user_profile.realm, event, bot_owner_user_ids(user_profile), ))
def notify_avatar_url_change(user_profile: UserProfile) -> None: if user_profile.is_bot: bot_event = dict( type="realm_bot", op="update", bot=dict( user_id=user_profile.id, avatar_url=avatar_url(user_profile), ), ) transaction.on_commit(lambda: send_event( user_profile.realm, bot_event, bot_owner_user_ids(user_profile), )) payload = dict( avatar_source=user_profile.avatar_source, avatar_url=avatar_url(user_profile), avatar_url_medium=avatar_url(user_profile, medium=True), avatar_version=user_profile.avatar_version, # Even clients using client_gravatar don't need the email, # since we're sending the URL anyway. user_id=user_profile.id, ) event = dict(type="realm_user", op="update", person=payload) transaction.on_commit(lambda: send_event( user_profile.realm, event, active_user_ids(user_profile.realm_id), ))
def do_change_full_name(user_profile: UserProfile, full_name: str, acting_user: Optional[UserProfile]) -> None: old_name = user_profile.full_name user_profile.full_name = full_name user_profile.save(update_fields=["full_name"]) event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, acting_user=acting_user, modified_user=user_profile, event_type=RealmAuditLog.USER_FULL_NAME_CHANGED, event_time=event_time, extra_data=old_name, ) payload = dict(user_id=user_profile.id, full_name=user_profile.full_name) send_event( user_profile.realm, dict(type="realm_user", op="update", person=payload), active_user_ids(user_profile.realm_id), ) if user_profile.is_bot: send_event( user_profile.realm, dict(type="realm_bot", op="update", bot=payload), bot_owner_user_ids(user_profile), )
def do_update_outgoing_webhook_service( bot_profile: UserProfile, service_interface: int, service_payload_url: str ) -> None: # TODO: First service is chosen because currently one bot can only have one service. # Update this once multiple services are supported. service = get_bot_services(bot_profile.id)[0] service.base_url = service_payload_url service.interface = service_interface service.save() send_event( bot_profile.realm, dict( type="realm_bot", op="update", bot=dict( user_id=bot_profile.id, services=[ dict( base_url=service.base_url, interface=service.interface, token=service.token ) ], ), ), bot_owner_user_ids(bot_profile), )
def do_update_bot_config_data(bot_profile: UserProfile, config_data: Dict[str, str]) -> None: for key, value in config_data.items(): set_bot_config(bot_profile, key, value) updated_config_data = get_bot_config(bot_profile) send_event( bot_profile.realm, dict( type="realm_bot", op="update", bot=dict( user_id=bot_profile.id, services=[dict(config_data=updated_config_data)], ), ), bot_owner_user_ids(bot_profile), )
def do_regenerate_api_key(user_profile: UserProfile, acting_user: UserProfile) -> str: old_api_key = user_profile.api_key new_api_key = generate_api_key() user_profile.api_key = new_api_key user_profile.save(update_fields=["api_key"]) # We need to explicitly delete the old API key from our caches, # because the on-save handler for flushing the UserProfile object # in zerver/lib/cache.py only has access to the new API key. cache_delete(user_profile_by_api_key_cache_key(old_api_key)) event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, acting_user=acting_user, modified_user=user_profile, event_type=RealmAuditLog.USER_API_KEY_CHANGED, event_time=event_time, ) if user_profile.is_bot: send_event( user_profile.realm, dict( type="realm_bot", op="update", bot=dict( user_id=user_profile.id, api_key=new_api_key, ), ), bot_owner_user_ids(user_profile), ) event = { "type": "clear_push_device_tokens", "user_profile_id": user_profile.id } queue_json_publish("deferred_work", event) return new_api_key
def do_change_default_events_register_stream( user_profile: UserProfile, stream: Optional[Stream], *, acting_user: Optional[UserProfile]) -> None: old_value = user_profile.default_events_register_stream_id user_profile.default_events_register_stream = stream user_profile.save(update_fields=["default_events_register_stream"]) event_time = timezone_now() RealmAuditLog.objects.create( realm=user_profile.realm, event_type=RealmAuditLog.USER_DEFAULT_REGISTER_STREAM_CHANGED, event_time=event_time, modified_user=user_profile, acting_user=acting_user, extra_data=orjson.dumps({ RealmAuditLog.OLD_VALUE: old_value, RealmAuditLog.NEW_VALUE: None if stream is None else stream.id, }).decode(), ) if user_profile.is_bot: if stream: stream_name: Optional[str] = stream.name else: stream_name = None event = dict( type="realm_bot", op="update", bot=dict( user_id=user_profile.id, default_events_register_stream=stream_name, ), ) transaction.on_commit(lambda: send_event( user_profile.realm, event, bot_owner_user_ids(user_profile), ))
def notify_created_bot(user_profile: UserProfile) -> None: event = created_bot_event(user_profile) send_event(user_profile.realm, event, bot_owner_user_ids(user_profile))
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, ), ) previous_owner_id = previous_owner.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_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))