mirror of
https://github.com/zulip/zulip.git
synced 2025-11-16 11:52:01 +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.
|
||||
|
||||
**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.
|
||||
|
||||
**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
|
||||
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`
|
||||
|
||||
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: :
|
||||
|
||||
def apply_events(state, events, user_profile):
|
||||
def apply_event(state, events, user_profile, include_subscribers):
|
||||
for event in events:
|
||||
# ...
|
||||
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):
|
||||
# type: (Dict[str, Any], Iterable[Dict[str, Any]], UserProfile, bool) -> None
|
||||
for event in events:
|
||||
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']
|
||||
apply_event(state, event, user_profile, include_subscribers)
|
||||
|
||||
def our_person(p):
|
||||
# type: (Dict[str, Any]) -> bool
|
||||
return p['user_id'] == person['user_id']
|
||||
def apply_event(state, event, user_profile, include_subscribers):
|
||||
# type: (Dict[str, Any], Dict[str, Any], UserProfile, bool) -> None
|
||||
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":
|
||||
state['realm_users'].append(person)
|
||||
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'])
|
||||
def our_person(p):
|
||||
# type: (Dict[str, Any]) -> bool
|
||||
return p['user_id'] == person['user_id']
|
||||
|
||||
if event['op'] == 'remove':
|
||||
email = event['bot']['email']
|
||||
state['realm_bots'] = [b for b in state['realm_bots'] if b['email'] != email]
|
||||
if event['op'] == "add":
|
||||
state['realm_users'].append(person)
|
||||
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':
|
||||
for bot in state['realm_bots']:
|
||||
if bot['email'] == event['bot']['email']:
|
||||
bot.update(event['bot'])
|
||||
if event['op'] == 'remove':
|
||||
email = event['bot']['email']
|
||||
state['realm_bots'] = [b for b in state['realm_bots'] if b['email'] != email]
|
||||
|
||||
elif event['type'] == 'stream':
|
||||
if event['op'] == 'create':
|
||||
for stream in event['streams']:
|
||||
if not stream['invite_only']:
|
||||
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':
|
||||
for bot in state['realm_bots']:
|
||||
if bot['email'] == event['bot']['email']:
|
||||
bot.update(event['bot'])
|
||||
|
||||
if event['op'] == 'delete':
|
||||
deleted_stream_ids = {stream['stream_id'] for stream in event['streams']}
|
||||
state['streams'] = [s for s in state['streams'] if s['stream_id'] not in deleted_stream_ids]
|
||||
state['never_subscribed'] = [stream for stream in state['never_subscribed'] if
|
||||
stream['stream_id'] not in deleted_stream_ids]
|
||||
elif event['type'] == 'stream':
|
||||
if event['op'] == 'create':
|
||||
for stream in event['streams']:
|
||||
if not stream['invite_only']:
|
||||
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':
|
||||
# For legacy reasons, we call stream data 'subscriptions' in
|
||||
# the state var here, for the benefit of the JS code.
|
||||
for obj in state['subscriptions']:
|
||||
if obj['name'].lower() == event['name'].lower():
|
||||
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'] == 'delete':
|
||||
deleted_stream_ids = {stream['stream_id'] for stream in event['streams']}
|
||||
state['streams'] = [s for s in state['streams'] if s['stream_id'] not in deleted_stream_ids]
|
||||
state['never_subscribed'] = [stream for stream in state['never_subscribed'] if
|
||||
stream['stream_id'] not in deleted_stream_ids]
|
||||
|
||||
if event['op'] in ["add"]:
|
||||
if include_subscribers:
|
||||
# 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'] == 'update':
|
||||
# For legacy reasons, we call stream data 'subscriptions' in
|
||||
# the state var here, for the benefit of the JS code.
|
||||
for obj in state['subscriptions']:
|
||||
if obj['name'].lower() == event['name'].lower():
|
||||
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']:
|
||||
return
|
||||
|
||||
def name(sub):
|
||||
# type: (Dict[str, Any]) -> Text
|
||||
return sub['name'].lower()
|
||||
if event['op'] in ["add"]:
|
||||
if include_subscribers:
|
||||
# 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":
|
||||
added_names = set(map(name, event["subscriptions"]))
|
||||
was_added = lambda s: name(s) in added_names
|
||||
def name(sub):
|
||||
# type: (Dict[str, Any]) -> Text
|
||||
return sub['name'].lower()
|
||||
|
||||
# add the new subscriptions
|
||||
state['subscriptions'] += event['subscriptions']
|
||||
if event['op'] == "add":
|
||||
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
|
||||
state['unsubscribed'] = [s for s in state['unsubscribed'] if not was_added(s)]
|
||||
# add the new subscriptions
|
||||
state['subscriptions'] += event['subscriptions']
|
||||
|
||||
# remove them from never_subscribed if they had been there
|
||||
state['never_subscribed'] = [s for s in state['never_subscribed'] if not was_added(s)]
|
||||
# remove them from unsubscribed if they had been there
|
||||
state['unsubscribed'] = [s for s in state['unsubscribed'] if not was_added(s)]
|
||||
|
||||
elif event['op'] == "remove":
|
||||
removed_names = set(map(name, event["subscriptions"]))
|
||||
was_removed = lambda s: name(s) in removed_names
|
||||
# remove them from never_subscribed if they had been there
|
||||
state['never_subscribed'] = [s for s in state['never_subscribed'] if not was_added(s)]
|
||||
|
||||
# Find the subs we are affecting.
|
||||
removed_subs = list(filter(was_removed, state['subscriptions']))
|
||||
elif event['op'] == "remove":
|
||||
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.
|
||||
if include_subscribers:
|
||||
for sub in removed_subs:
|
||||
sub['subscribers'] = [id for id in sub['subscribers'] if id != user_profile.id]
|
||||
# Find the subs we are affecting.
|
||||
removed_subs = list(filter(was_removed, state['subscriptions']))
|
||||
|
||||
# We must effectively copy the removed subscriptions from subscriptions to
|
||||
# unsubscribe, since we only have the name in our data structure.
|
||||
state['unsubscribed'] += removed_subs
|
||||
# Remove our user from the subscribers of the removed subscriptions.
|
||||
if include_subscribers:
|
||||
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.
|
||||
state['subscriptions'] = [s for s in state['subscriptions'] if not was_removed(s)]
|
||||
# We must effectively copy the removed subscriptions from subscriptions to
|
||||
# unsubscribe, since we only have the name in our data structure.
|
||||
state['unsubscribed'] += removed_subs
|
||||
|
||||
elif event['op'] == 'update':
|
||||
for sub in state['subscriptions']:
|
||||
if sub['name'].lower() == event['name'].lower():
|
||||
sub[event['property']] = event['value']
|
||||
elif event['op'] == 'peer_add':
|
||||
user_id = event['user_id']
|
||||
for sub in state['subscriptions']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id not in sub['subscribers']):
|
||||
sub['subscribers'].append(user_id)
|
||||
for sub in state['never_subscribed']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id not in sub['subscribers']):
|
||||
sub['subscribers'].append(user_id)
|
||||
elif event['op'] == 'peer_remove':
|
||||
user_id = event['user_id']
|
||||
for sub in state['subscriptions']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id in sub['subscribers']):
|
||||
sub['subscribers'].remove(user_id)
|
||||
elif event['type'] == "presence":
|
||||
state['presences'][event['email']] = event['presence']
|
||||
elif event['type'] == "update_message":
|
||||
# The client will get the updated message directly
|
||||
pass
|
||||
elif event['type'] == "reaction":
|
||||
# The client will get the message with the reactions directly
|
||||
pass
|
||||
elif event['type'] == "referral":
|
||||
state['referrals'] = event['referrals']
|
||||
elif event['type'] == "update_message_flags":
|
||||
# The client will get the message with the updated flags directly
|
||||
pass
|
||||
elif event['type'] == "realm_domains":
|
||||
if event['op'] == 'add':
|
||||
state['realm_domains'].append(event['alias'])
|
||||
elif event['op'] == 'change':
|
||||
for realm_domain in state['realm_domains']:
|
||||
if realm_domain['domain'] == event['alias']['domain']:
|
||||
realm_domain['allow_subdomains'] = event['alias']['allow_subdomains']
|
||||
elif event['op'] == 'remove':
|
||||
state['realm_domains'] = [alias for alias in state['realm_domains'] if alias['domain'] != event['domain']]
|
||||
elif event['type'] == "realm_emoji":
|
||||
state['realm_emoji'] = event['realm_emoji']
|
||||
elif event['type'] == "alert_words":
|
||||
state['alert_words'] = event['alert_words']
|
||||
elif event['type'] == "muted_topics":
|
||||
state['muted_topics'] = event["muted_topics"]
|
||||
elif event['type'] == "realm_filters":
|
||||
state['realm_filters'] = event["realm_filters"]
|
||||
elif event['type'] == "update_display_settings":
|
||||
if event['setting_name'] == "twenty_four_hour_time":
|
||||
state['twenty_four_hour_time'] = event["setting"]
|
||||
if event['setting_name'] == 'left_side_userlist':
|
||||
state['left_side_userlist'] = event["setting"]
|
||||
elif event['type'] == "update_global_notifications":
|
||||
if event['notification_name'] == "enable_stream_desktop_notifications":
|
||||
state['enable_stream_desktop_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_stream_sounds":
|
||||
state['enable_stream_sounds'] = event['setting']
|
||||
elif event['notification_name'] == "enable_desktop_notifications":
|
||||
state['enable_desktop_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_sounds":
|
||||
state['enable_sounds'] = event['setting']
|
||||
elif event['notification_name'] == "enable_offline_email_notifications":
|
||||
state['enable_offline_email_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_offline_push_notifications":
|
||||
state['enable_offline_push_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_online_push_notifications":
|
||||
state['enable_online_push_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_digest_emails":
|
||||
state['enable_digest_emails'] = event['setting']
|
||||
else:
|
||||
raise ValueError("Unexpected event type %s" % (event['type'],))
|
||||
# Now filter out the removed subscriptions from subscriptions.
|
||||
state['subscriptions'] = [s for s in state['subscriptions'] if not was_removed(s)]
|
||||
|
||||
elif event['op'] == 'update':
|
||||
for sub in state['subscriptions']:
|
||||
if sub['name'].lower() == event['name'].lower():
|
||||
sub[event['property']] = event['value']
|
||||
elif event['op'] == 'peer_add':
|
||||
user_id = event['user_id']
|
||||
for sub in state['subscriptions']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id not in sub['subscribers']):
|
||||
sub['subscribers'].append(user_id)
|
||||
for sub in state['never_subscribed']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id not in sub['subscribers']):
|
||||
sub['subscribers'].append(user_id)
|
||||
elif event['op'] == 'peer_remove':
|
||||
user_id = event['user_id']
|
||||
for sub in state['subscriptions']:
|
||||
if (sub['name'] in event['subscriptions'] and
|
||||
user_id in sub['subscribers']):
|
||||
sub['subscribers'].remove(user_id)
|
||||
elif event['type'] == "presence":
|
||||
state['presences'][event['email']] = event['presence']
|
||||
elif event['type'] == "update_message":
|
||||
# The client will get the updated message directly
|
||||
pass
|
||||
elif event['type'] == "reaction":
|
||||
# The client will get the message with the reactions directly
|
||||
pass
|
||||
elif event['type'] == "referral":
|
||||
state['referrals'] = event['referrals']
|
||||
elif event['type'] == "update_message_flags":
|
||||
# The client will get the message with the updated flags directly
|
||||
pass
|
||||
elif event['type'] == "realm_domains":
|
||||
if event['op'] == 'add':
|
||||
state['realm_domains'].append(event['alias'])
|
||||
elif event['op'] == 'change':
|
||||
for realm_domain in state['realm_domains']:
|
||||
if realm_domain['domain'] == event['alias']['domain']:
|
||||
realm_domain['allow_subdomains'] = event['alias']['allow_subdomains']
|
||||
elif event['op'] == 'remove':
|
||||
state['realm_domains'] = [alias for alias in state['realm_domains'] if alias['domain'] != event['domain']]
|
||||
elif event['type'] == "realm_emoji":
|
||||
state['realm_emoji'] = event['realm_emoji']
|
||||
elif event['type'] == "alert_words":
|
||||
state['alert_words'] = event['alert_words']
|
||||
elif event['type'] == "muted_topics":
|
||||
state['muted_topics'] = event["muted_topics"]
|
||||
elif event['type'] == "realm_filters":
|
||||
state['realm_filters'] = event["realm_filters"]
|
||||
elif event['type'] == "update_display_settings":
|
||||
if event['setting_name'] == "twenty_four_hour_time":
|
||||
state['twenty_four_hour_time'] = event["setting"]
|
||||
if event['setting_name'] == 'left_side_userlist':
|
||||
state['left_side_userlist'] = event["setting"]
|
||||
elif event['type'] == "update_global_notifications":
|
||||
if event['notification_name'] == "enable_stream_desktop_notifications":
|
||||
state['enable_stream_desktop_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_stream_sounds":
|
||||
state['enable_stream_sounds'] = event['setting']
|
||||
elif event['notification_name'] == "enable_desktop_notifications":
|
||||
state['enable_desktop_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_sounds":
|
||||
state['enable_sounds'] = event['setting']
|
||||
elif event['notification_name'] == "enable_offline_email_notifications":
|
||||
state['enable_offline_email_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_offline_push_notifications":
|
||||
state['enable_offline_push_notifications'] = event['setting']
|
||||
elif event['notification_name'] == "enable_online_push_notifications":
|
||||
state['enable_online_push_notifications'] = event['setting']
|
||||
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,
|
||||
event_types=None, queue_lifespan_secs=0, all_public_streams=False,
|
||||
|
||||
Reference in New Issue
Block a user