mirror of
https://github.com/zulip/zulip.git
synced 2025-11-12 01:47:41 +00:00
events: Extract apply_event helper.
This mostly just saves us a level of messy indentation.
This commit is contained in:
@@ -36,7 +36,7 @@ interacting with the database in `zerver/lib/actions.py`. It should
|
|||||||
update the database and send an event announcing the change.
|
update the database and send an event announcing the change.
|
||||||
|
|
||||||
**Application state:** Modify the `fetch_initial_state_data` and
|
**Application state:** Modify the `fetch_initial_state_data` and
|
||||||
`apply_events` functions in `zerver/lib/actions.py` to update the state
|
`apply_event` functions in `zerver/lib/actions.py` to update the state
|
||||||
based on the event you just created.
|
based on the event you just created.
|
||||||
|
|
||||||
**Backend implementation:** Make any other modifications to the backend
|
**Backend implementation:** Make any other modifications to the backend
|
||||||
@@ -182,16 +182,16 @@ realm. :
|
|||||||
|
|
||||||
You then need to add code that will handle the event and update the
|
You then need to add code that will handle the event and update the
|
||||||
application state. In `zerver/lib/events.py` update the
|
application state. In `zerver/lib/events.py` update the
|
||||||
`fetch_initial_state` and `apply_events` functions. :
|
`fetch_initial_state` and `apply_event` functions. :
|
||||||
|
|
||||||
def fetch_initial_state_data(user_profile, event_types, queue_id):
|
def fetch_initial_state_data(user_profile, event_types, queue_id, include_subscribers=True):
|
||||||
# ...
|
# ...
|
||||||
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
|
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
|
||||||
|
|
||||||
In this case you don't need to change `apply_events` because there is
|
In this case you don't need to change `apply_event` because there is
|
||||||
already code that will correctly handle the realm update event type: :
|
already code that will correctly handle the realm update event type: :
|
||||||
|
|
||||||
def apply_events(state, events, user_profile):
|
def apply_event(state, events, user_profile, include_subscribers):
|
||||||
for event in events:
|
for event in events:
|
||||||
# ...
|
# ...
|
||||||
elif event['type'] == 'realm':
|
elif event['type'] == 'realm':
|
||||||
|
|||||||
@@ -152,219 +152,223 @@ def fetch_initial_state_data(user_profile, event_types, queue_id,
|
|||||||
def apply_events(state, events, user_profile, include_subscribers=True):
|
def apply_events(state, events, user_profile, include_subscribers=True):
|
||||||
# type: (Dict[str, Any], Iterable[Dict[str, Any]], UserProfile, bool) -> None
|
# type: (Dict[str, Any], Iterable[Dict[str, Any]], UserProfile, bool) -> None
|
||||||
for event in events:
|
for event in events:
|
||||||
if event['type'] == "message":
|
apply_event(state, event, user_profile, include_subscribers)
|
||||||
state['max_message_id'] = max(state['max_message_id'], event['message']['id'])
|
|
||||||
elif event['type'] == "pointer":
|
|
||||||
state['pointer'] = max(state['pointer'], event['pointer'])
|
|
||||||
elif event['type'] == "realm_user":
|
|
||||||
person = event['person']
|
|
||||||
|
|
||||||
def our_person(p):
|
def apply_event(state, event, user_profile, include_subscribers):
|
||||||
# type: (Dict[str, Any]) -> bool
|
# type: (Dict[str, Any], Dict[str, Any], UserProfile, bool) -> None
|
||||||
return p['user_id'] == person['user_id']
|
if event['type'] == "message":
|
||||||
|
state['max_message_id'] = max(state['max_message_id'], event['message']['id'])
|
||||||
|
elif event['type'] == "pointer":
|
||||||
|
state['pointer'] = max(state['pointer'], event['pointer'])
|
||||||
|
elif event['type'] == "realm_user":
|
||||||
|
person = event['person']
|
||||||
|
|
||||||
if event['op'] == "add":
|
def our_person(p):
|
||||||
state['realm_users'].append(person)
|
# type: (Dict[str, Any]) -> bool
|
||||||
elif event['op'] == "remove":
|
return p['user_id'] == person['user_id']
|
||||||
state['realm_users'] = [user for user in state['realm_users'] if not our_person(user)]
|
|
||||||
elif event['op'] == 'update':
|
|
||||||
for p in state['realm_users']:
|
|
||||||
if our_person(p):
|
|
||||||
# In the unlikely event that the current user
|
|
||||||
# just changed to/from being an admin, we need
|
|
||||||
# to add/remove the data on all bots in the
|
|
||||||
# realm. This is ugly and probably better
|
|
||||||
# solved by removing the all-realm-bots data
|
|
||||||
# given to admin users from this flow.
|
|
||||||
if ('is_admin' in person and 'realm_bots' in state and
|
|
||||||
user_profile.email == person['email']):
|
|
||||||
if p['is_admin'] and not person['is_admin']:
|
|
||||||
state['realm_bots'] = []
|
|
||||||
if not p['is_admin'] and person['is_admin']:
|
|
||||||
state['realm_bots'] = get_owned_bot_dicts(user_profile)
|
|
||||||
# Now update the person
|
|
||||||
p.update(person)
|
|
||||||
elif event['type'] == 'realm_bot':
|
|
||||||
if event['op'] == 'add':
|
|
||||||
state['realm_bots'].append(event['bot'])
|
|
||||||
|
|
||||||
if event['op'] == 'remove':
|
if event['op'] == "add":
|
||||||
email = event['bot']['email']
|
state['realm_users'].append(person)
|
||||||
state['realm_bots'] = [b for b in state['realm_bots'] if b['email'] != email]
|
elif event['op'] == "remove":
|
||||||
|
state['realm_users'] = [user for user in state['realm_users'] if not our_person(user)]
|
||||||
|
elif event['op'] == 'update':
|
||||||
|
for p in state['realm_users']:
|
||||||
|
if our_person(p):
|
||||||
|
# In the unlikely event that the current user
|
||||||
|
# just changed to/from being an admin, we need
|
||||||
|
# to add/remove the data on all bots in the
|
||||||
|
# realm. This is ugly and probably better
|
||||||
|
# solved by removing the all-realm-bots data
|
||||||
|
# given to admin users from this flow.
|
||||||
|
if ('is_admin' in person and 'realm_bots' in state and
|
||||||
|
user_profile.email == person['email']):
|
||||||
|
if p['is_admin'] and not person['is_admin']:
|
||||||
|
state['realm_bots'] = []
|
||||||
|
if not p['is_admin'] and person['is_admin']:
|
||||||
|
state['realm_bots'] = get_owned_bot_dicts(user_profile)
|
||||||
|
# Now update the person
|
||||||
|
p.update(person)
|
||||||
|
elif event['type'] == 'realm_bot':
|
||||||
|
if event['op'] == 'add':
|
||||||
|
state['realm_bots'].append(event['bot'])
|
||||||
|
|
||||||
if event['op'] == 'update':
|
if event['op'] == 'remove':
|
||||||
for bot in state['realm_bots']:
|
email = event['bot']['email']
|
||||||
if bot['email'] == event['bot']['email']:
|
state['realm_bots'] = [b for b in state['realm_bots'] if b['email'] != email]
|
||||||
bot.update(event['bot'])
|
|
||||||
|
|
||||||
elif event['type'] == 'stream':
|
if event['op'] == 'update':
|
||||||
if event['op'] == 'create':
|
for bot in state['realm_bots']:
|
||||||
for stream in event['streams']:
|
if bot['email'] == event['bot']['email']:
|
||||||
if not stream['invite_only']:
|
bot.update(event['bot'])
|
||||||
stream_data = copy.deepcopy(stream)
|
|
||||||
if include_subscribers:
|
|
||||||
stream_data['subscribers'] = []
|
|
||||||
# Add stream to never_subscribed (if not invite_only)
|
|
||||||
state['never_subscribed'].append(stream_data)
|
|
||||||
|
|
||||||
if event['op'] == 'delete':
|
elif event['type'] == 'stream':
|
||||||
deleted_stream_ids = {stream['stream_id'] for stream in event['streams']}
|
if event['op'] == 'create':
|
||||||
state['streams'] = [s for s in state['streams'] if s['stream_id'] not in deleted_stream_ids]
|
for stream in event['streams']:
|
||||||
state['never_subscribed'] = [stream for stream in state['never_subscribed'] if
|
if not stream['invite_only']:
|
||||||
stream['stream_id'] not in deleted_stream_ids]
|
stream_data = copy.deepcopy(stream)
|
||||||
|
if include_subscribers:
|
||||||
|
stream_data['subscribers'] = []
|
||||||
|
# Add stream to never_subscribed (if not invite_only)
|
||||||
|
state['never_subscribed'].append(stream_data)
|
||||||
|
|
||||||
if event['op'] == 'update':
|
if event['op'] == 'delete':
|
||||||
# For legacy reasons, we call stream data 'subscriptions' in
|
deleted_stream_ids = {stream['stream_id'] for stream in event['streams']}
|
||||||
# the state var here, for the benefit of the JS code.
|
state['streams'] = [s for s in state['streams'] if s['stream_id'] not in deleted_stream_ids]
|
||||||
for obj in state['subscriptions']:
|
state['never_subscribed'] = [stream for stream in state['never_subscribed'] if
|
||||||
if obj['name'].lower() == event['name'].lower():
|
stream['stream_id'] not in deleted_stream_ids]
|
||||||
obj[event['property']] = event['value']
|
|
||||||
# Also update the pure streams data
|
|
||||||
for stream in state['streams']:
|
|
||||||
if stream['name'].lower() == event['name'].lower():
|
|
||||||
prop = event['property']
|
|
||||||
if prop in stream:
|
|
||||||
stream[prop] = event['value']
|
|
||||||
elif event['op'] == "occupy":
|
|
||||||
state['streams'] += event['streams']
|
|
||||||
elif event['op'] == "vacate":
|
|
||||||
stream_ids = [s["stream_id"] for s in event['streams']]
|
|
||||||
state['streams'] = [s for s in state['streams'] if s["stream_id"] not in stream_ids]
|
|
||||||
elif event['type'] == 'default_streams':
|
|
||||||
state['realm_default_streams'] = event['default_streams']
|
|
||||||
elif event['type'] == 'realm':
|
|
||||||
if event['op'] == "update":
|
|
||||||
field = 'realm_' + event['property']
|
|
||||||
state[field] = event['value']
|
|
||||||
elif event['op'] == "update_dict":
|
|
||||||
for key, value in event['data'].items():
|
|
||||||
state['realm_' + key] = value
|
|
||||||
elif event['type'] == "subscription":
|
|
||||||
if not include_subscribers and event['op'] in ['peer_add', 'peer_remove']:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if event['op'] in ["add"]:
|
if event['op'] == 'update':
|
||||||
if include_subscribers:
|
# For legacy reasons, we call stream data 'subscriptions' in
|
||||||
# Convert the emails to user_profile IDs since that's what register() returns
|
# the state var here, for the benefit of the JS code.
|
||||||
# TODO: Clean up this situation by making the event also have IDs
|
for obj in state['subscriptions']:
|
||||||
for item in event["subscriptions"]:
|
if obj['name'].lower() == event['name'].lower():
|
||||||
item["subscribers"] = [get_user_profile_by_email(email).id for email in item["subscribers"]]
|
obj[event['property']] = event['value']
|
||||||
else:
|
# Also update the pure streams data
|
||||||
# Avoid letting 'subscribers' entries end up in the list
|
for stream in state['streams']:
|
||||||
for i, sub in enumerate(event['subscriptions']):
|
if stream['name'].lower() == event['name'].lower():
|
||||||
event['subscriptions'][i] = copy.deepcopy(event['subscriptions'][i])
|
prop = event['property']
|
||||||
del event['subscriptions'][i]['subscribers']
|
if prop in stream:
|
||||||
|
stream[prop] = event['value']
|
||||||
|
elif event['op'] == "occupy":
|
||||||
|
state['streams'] += event['streams']
|
||||||
|
elif event['op'] == "vacate":
|
||||||
|
stream_ids = [s["stream_id"] for s in event['streams']]
|
||||||
|
state['streams'] = [s for s in state['streams'] if s["stream_id"] not in stream_ids]
|
||||||
|
elif event['type'] == 'default_streams':
|
||||||
|
state['realm_default_streams'] = event['default_streams']
|
||||||
|
elif event['type'] == 'realm':
|
||||||
|
if event['op'] == "update":
|
||||||
|
field = 'realm_' + event['property']
|
||||||
|
state[field] = event['value']
|
||||||
|
elif event['op'] == "update_dict":
|
||||||
|
for key, value in event['data'].items():
|
||||||
|
state['realm_' + key] = value
|
||||||
|
elif event['type'] == "subscription":
|
||||||
|
if not include_subscribers and event['op'] in ['peer_add', 'peer_remove']:
|
||||||
|
return
|
||||||
|
|
||||||
def name(sub):
|
if event['op'] in ["add"]:
|
||||||
# type: (Dict[str, Any]) -> Text
|
if include_subscribers:
|
||||||
return sub['name'].lower()
|
# Convert the emails to user_profile IDs since that's what register() returns
|
||||||
|
# TODO: Clean up this situation by making the event also have IDs
|
||||||
|
for item in event["subscriptions"]:
|
||||||
|
item["subscribers"] = [get_user_profile_by_email(email).id for email in item["subscribers"]]
|
||||||
|
else:
|
||||||
|
# Avoid letting 'subscribers' entries end up in the list
|
||||||
|
for i, sub in enumerate(event['subscriptions']):
|
||||||
|
event['subscriptions'][i] = copy.deepcopy(event['subscriptions'][i])
|
||||||
|
del event['subscriptions'][i]['subscribers']
|
||||||
|
|
||||||
if event['op'] == "add":
|
def name(sub):
|
||||||
added_names = set(map(name, event["subscriptions"]))
|
# type: (Dict[str, Any]) -> Text
|
||||||
was_added = lambda s: name(s) in added_names
|
return sub['name'].lower()
|
||||||
|
|
||||||
# add the new subscriptions
|
if event['op'] == "add":
|
||||||
state['subscriptions'] += event['subscriptions']
|
added_names = set(map(name, event["subscriptions"]))
|
||||||
|
was_added = lambda s: name(s) in added_names
|
||||||
|
|
||||||
# remove them from unsubscribed if they had been there
|
# add the new subscriptions
|
||||||
state['unsubscribed'] = [s for s in state['unsubscribed'] if not was_added(s)]
|
state['subscriptions'] += event['subscriptions']
|
||||||
|
|
||||||
# remove them from never_subscribed if they had been there
|
# remove them from unsubscribed if they had been there
|
||||||
state['never_subscribed'] = [s for s in state['never_subscribed'] if not was_added(s)]
|
state['unsubscribed'] = [s for s in state['unsubscribed'] if not was_added(s)]
|
||||||
|
|
||||||
elif event['op'] == "remove":
|
# remove them from never_subscribed if they had been there
|
||||||
removed_names = set(map(name, event["subscriptions"]))
|
state['never_subscribed'] = [s for s in state['never_subscribed'] if not was_added(s)]
|
||||||
was_removed = lambda s: name(s) in removed_names
|
|
||||||
|
|
||||||
# Find the subs we are affecting.
|
elif event['op'] == "remove":
|
||||||
removed_subs = list(filter(was_removed, state['subscriptions']))
|
removed_names = set(map(name, event["subscriptions"]))
|
||||||
|
was_removed = lambda s: name(s) in removed_names
|
||||||
|
|
||||||
# Remove our user from the subscribers of the removed subscriptions.
|
# Find the subs we are affecting.
|
||||||
if include_subscribers:
|
removed_subs = list(filter(was_removed, state['subscriptions']))
|
||||||
for sub in removed_subs:
|
|
||||||
sub['subscribers'] = [id for id in sub['subscribers'] if id != user_profile.id]
|
|
||||||
|
|
||||||
# We must effectively copy the removed subscriptions from subscriptions to
|
# Remove our user from the subscribers of the removed subscriptions.
|
||||||
# unsubscribe, since we only have the name in our data structure.
|
if include_subscribers:
|
||||||
state['unsubscribed'] += removed_subs
|
for sub in removed_subs:
|
||||||
|
sub['subscribers'] = [id for id in sub['subscribers'] if id != user_profile.id]
|
||||||
|
|
||||||
# Now filter out the removed subscriptions from subscriptions.
|
# We must effectively copy the removed subscriptions from subscriptions to
|
||||||
state['subscriptions'] = [s for s in state['subscriptions'] if not was_removed(s)]
|
# unsubscribe, since we only have the name in our data structure.
|
||||||
|
state['unsubscribed'] += removed_subs
|
||||||
|
|
||||||
elif event['op'] == 'update':
|
# Now filter out the removed subscriptions from subscriptions.
|
||||||
for sub in state['subscriptions']:
|
state['subscriptions'] = [s for s in state['subscriptions'] if not was_removed(s)]
|
||||||
if sub['name'].lower() == event['name'].lower():
|
|
||||||
sub[event['property']] = event['value']
|
elif event['op'] == 'update':
|
||||||
elif event['op'] == 'peer_add':
|
for sub in state['subscriptions']:
|
||||||
user_id = event['user_id']
|
if sub['name'].lower() == event['name'].lower():
|
||||||
for sub in state['subscriptions']:
|
sub[event['property']] = event['value']
|
||||||
if (sub['name'] in event['subscriptions'] and
|
elif event['op'] == 'peer_add':
|
||||||
user_id not in sub['subscribers']):
|
user_id = event['user_id']
|
||||||
sub['subscribers'].append(user_id)
|
for sub in state['subscriptions']:
|
||||||
for sub in state['never_subscribed']:
|
if (sub['name'] in event['subscriptions'] and
|
||||||
if (sub['name'] in event['subscriptions'] and
|
user_id not in sub['subscribers']):
|
||||||
user_id not in sub['subscribers']):
|
sub['subscribers'].append(user_id)
|
||||||
sub['subscribers'].append(user_id)
|
for sub in state['never_subscribed']:
|
||||||
elif event['op'] == 'peer_remove':
|
if (sub['name'] in event['subscriptions'] and
|
||||||
user_id = event['user_id']
|
user_id not in sub['subscribers']):
|
||||||
for sub in state['subscriptions']:
|
sub['subscribers'].append(user_id)
|
||||||
if (sub['name'] in event['subscriptions'] and
|
elif event['op'] == 'peer_remove':
|
||||||
user_id in sub['subscribers']):
|
user_id = event['user_id']
|
||||||
sub['subscribers'].remove(user_id)
|
for sub in state['subscriptions']:
|
||||||
elif event['type'] == "presence":
|
if (sub['name'] in event['subscriptions'] and
|
||||||
state['presences'][event['email']] = event['presence']
|
user_id in sub['subscribers']):
|
||||||
elif event['type'] == "update_message":
|
sub['subscribers'].remove(user_id)
|
||||||
# The client will get the updated message directly
|
elif event['type'] == "presence":
|
||||||
pass
|
state['presences'][event['email']] = event['presence']
|
||||||
elif event['type'] == "reaction":
|
elif event['type'] == "update_message":
|
||||||
# The client will get the message with the reactions directly
|
# The client will get the updated message directly
|
||||||
pass
|
pass
|
||||||
elif event['type'] == "referral":
|
elif event['type'] == "reaction":
|
||||||
state['referrals'] = event['referrals']
|
# The client will get the message with the reactions directly
|
||||||
elif event['type'] == "update_message_flags":
|
pass
|
||||||
# The client will get the message with the updated flags directly
|
elif event['type'] == "referral":
|
||||||
pass
|
state['referrals'] = event['referrals']
|
||||||
elif event['type'] == "realm_domains":
|
elif event['type'] == "update_message_flags":
|
||||||
if event['op'] == 'add':
|
# The client will get the message with the updated flags directly
|
||||||
state['realm_domains'].append(event['alias'])
|
pass
|
||||||
elif event['op'] == 'change':
|
elif event['type'] == "realm_domains":
|
||||||
for realm_domain in state['realm_domains']:
|
if event['op'] == 'add':
|
||||||
if realm_domain['domain'] == event['alias']['domain']:
|
state['realm_domains'].append(event['alias'])
|
||||||
realm_domain['allow_subdomains'] = event['alias']['allow_subdomains']
|
elif event['op'] == 'change':
|
||||||
elif event['op'] == 'remove':
|
for realm_domain in state['realm_domains']:
|
||||||
state['realm_domains'] = [alias for alias in state['realm_domains'] if alias['domain'] != event['domain']]
|
if realm_domain['domain'] == event['alias']['domain']:
|
||||||
elif event['type'] == "realm_emoji":
|
realm_domain['allow_subdomains'] = event['alias']['allow_subdomains']
|
||||||
state['realm_emoji'] = event['realm_emoji']
|
elif event['op'] == 'remove':
|
||||||
elif event['type'] == "alert_words":
|
state['realm_domains'] = [alias for alias in state['realm_domains'] if alias['domain'] != event['domain']]
|
||||||
state['alert_words'] = event['alert_words']
|
elif event['type'] == "realm_emoji":
|
||||||
elif event['type'] == "muted_topics":
|
state['realm_emoji'] = event['realm_emoji']
|
||||||
state['muted_topics'] = event["muted_topics"]
|
elif event['type'] == "alert_words":
|
||||||
elif event['type'] == "realm_filters":
|
state['alert_words'] = event['alert_words']
|
||||||
state['realm_filters'] = event["realm_filters"]
|
elif event['type'] == "muted_topics":
|
||||||
elif event['type'] == "update_display_settings":
|
state['muted_topics'] = event["muted_topics"]
|
||||||
if event['setting_name'] == "twenty_four_hour_time":
|
elif event['type'] == "realm_filters":
|
||||||
state['twenty_four_hour_time'] = event["setting"]
|
state['realm_filters'] = event["realm_filters"]
|
||||||
if event['setting_name'] == 'left_side_userlist':
|
elif event['type'] == "update_display_settings":
|
||||||
state['left_side_userlist'] = event["setting"]
|
if event['setting_name'] == "twenty_four_hour_time":
|
||||||
elif event['type'] == "update_global_notifications":
|
state['twenty_four_hour_time'] = event["setting"]
|
||||||
if event['notification_name'] == "enable_stream_desktop_notifications":
|
if event['setting_name'] == 'left_side_userlist':
|
||||||
state['enable_stream_desktop_notifications'] = event['setting']
|
state['left_side_userlist'] = event["setting"]
|
||||||
elif event['notification_name'] == "enable_stream_sounds":
|
elif event['type'] == "update_global_notifications":
|
||||||
state['enable_stream_sounds'] = event['setting']
|
if event['notification_name'] == "enable_stream_desktop_notifications":
|
||||||
elif event['notification_name'] == "enable_desktop_notifications":
|
state['enable_stream_desktop_notifications'] = event['setting']
|
||||||
state['enable_desktop_notifications'] = event['setting']
|
elif event['notification_name'] == "enable_stream_sounds":
|
||||||
elif event['notification_name'] == "enable_sounds":
|
state['enable_stream_sounds'] = event['setting']
|
||||||
state['enable_sounds'] = event['setting']
|
elif event['notification_name'] == "enable_desktop_notifications":
|
||||||
elif event['notification_name'] == "enable_offline_email_notifications":
|
state['enable_desktop_notifications'] = event['setting']
|
||||||
state['enable_offline_email_notifications'] = event['setting']
|
elif event['notification_name'] == "enable_sounds":
|
||||||
elif event['notification_name'] == "enable_offline_push_notifications":
|
state['enable_sounds'] = event['setting']
|
||||||
state['enable_offline_push_notifications'] = event['setting']
|
elif event['notification_name'] == "enable_offline_email_notifications":
|
||||||
elif event['notification_name'] == "enable_online_push_notifications":
|
state['enable_offline_email_notifications'] = event['setting']
|
||||||
state['enable_online_push_notifications'] = event['setting']
|
elif event['notification_name'] == "enable_offline_push_notifications":
|
||||||
elif event['notification_name'] == "enable_digest_emails":
|
state['enable_offline_push_notifications'] = event['setting']
|
||||||
state['enable_digest_emails'] = event['setting']
|
elif event['notification_name'] == "enable_online_push_notifications":
|
||||||
else:
|
state['enable_online_push_notifications'] = event['setting']
|
||||||
raise ValueError("Unexpected event type %s" % (event['type'],))
|
elif event['notification_name'] == "enable_digest_emails":
|
||||||
|
state['enable_digest_emails'] = event['setting']
|
||||||
|
else:
|
||||||
|
raise ValueError("Unexpected event type %s" % (event['type'],))
|
||||||
|
|
||||||
def do_events_register(user_profile, user_client, apply_markdown=True,
|
def do_events_register(user_profile, user_client, apply_markdown=True,
|
||||||
event_types=None, queue_lifespan_secs=0, all_public_streams=False,
|
event_types=None, queue_lifespan_secs=0, all_public_streams=False,
|
||||||
|
|||||||
Reference in New Issue
Block a user