def _Notify(self): """Creates notifications: 1. Notifies removed followers that conversation has new activity. 2. Notifies users with contacts that have become prospective users. 3. Notifies existing followers of the viewpoint that new followers have been added. 4. Notifies new followers that they have been added to a viewpoint. """ # Creates notifications for any new prospective users. identity_keys = [ contact_dict['identity'] for contact_dict, ( user_exists, user_id, webapp_dev_id) in zip(self._contact_dicts, self._contact_ids) if not user_exists ] yield NotificationManager.NotifyCreateProspective( self._client, identity_keys, self._op.timestamp) # Creates notifications for any revived followers. yield NotificationManager.NotifyReviveFollowers( self._client, self._viewpoint_id, self._revive_follower_ids, self._op.timestamp) # Creates notification of new viewpoint for each new follower. yield NotificationManager.NotifyAddFollowers( self._client, self._viewpoint_id, self._existing_followers, self._new_followers, self._contact_user_ids, self._act_dict, self._op.timestamp)
def _Notify(self): """Creates notifications: 1. Notifies removed followers that conversation has new activity. 2. Notifies users with contacts that have become prospective users. 3. Notifies existing followers of the viewpoint that new followers have been added. 4. Notifies new followers that they have been added to a viewpoint. """ # Creates notifications for any new prospective users. identity_keys = [ contact_dict['identity'] for contact_dict, ( user_exists, user_id, webapp_dev_id) in zip(self._contact_dicts, self._contact_ids) if not user_exists ] yield NotificationManager.NotifyCreateProspective( self._client, identity_keys, self._op.timestamp) # Notify followers of the changes made by the share operation. yield NotificationManager.NotifyShareNew(self._client, self._vp_dict, self._followers, self._contact_user_ids, self._act_dict, self._ep_dicts, self._op.timestamp)
def _Notify(self): """Creates notifications: 1. Notifies removed followers that conversation has new activity. 2. Notifies existing followers of the viewpoint that photos have been added. """ # Creates notifications for any revived followers. yield NotificationManager.NotifyReviveFollowers( self._client, self._viewpoint_id, self._revive_follower_ids, self._op.timestamp) # Notify followers of the changes made by the share operation. yield NotificationManager.NotifyShareExisting( self._client, self._viewpoint_id, self._followers, self._act_dict, self._ep_dicts, self._need_cover_photo)
def _Notify(self): """Creates notifications: 1. Notifies removed followers that conversation has new activity. 2. Notifies existing followers of the viewpoint that metadata has changed. """ # Creates notifications for any revived followers. yield NotificationManager.NotifyReviveFollowers( self._client, self._viewpoint_id, self._revive_follower_ids, self._op.timestamp) # Notifies followers that viewpoint metadata has changed. yield NotificationManager.NotifyUpdateViewpoint( self._client, self._vp_dict, self._followers, self._prev_values, self._act_dict)
def _Notify(self): """Creates notifications: 1. Notify all of the user's devices that photos have been removed from the viewpoint. """ yield NotificationManager.NotifyRemovePhotos(self._client, self._user.user_id, self._ep_dicts)
def _MergeIdentities(self): """Re-binds all identities attached to the source user to the target user. Sends corresponding notifications for any merged identities. Sets a checkpoint so that the exact same set of identities will be merged if a restart occurs. """ if self._op.checkpoint is None: # Get set of identities that need to re-bound to the target user. query_expr = ('identity.user_id={id}', {'id': self._source_user_id}) identity_keys = yield gen.Task(Identity.IndexQueryKeys, self._client, query_expr, limit=MergeAccountsOperation._MAX_IDENTITIES) checkpoint = {'state': 'id', 'ids': [key.hash_key for key in identity_keys]} yield self._op.SetCheckpoint(self._client, checkpoint) else: identity_keys = [DBKey(id, None) for id in self._op.checkpoint['ids']] # Get all the identity objects and re-bind them to the target user. identities = yield gen.Task(Identity.BatchQuery, self._client, identity_keys, None) for identity in identities: identity.expires = 0 identity.user_id = self._target_user_id yield gen.Task(identity.Update, self._client) # Send notifications for all identities that were re-bound. yield NotificationManager.NotifyMergeIdentities(self._client, self._target_user_id, [identity.key for identity in identities], self._op.timestamp)
def _Notify(self): """Creates notifications: Notify of all contacts with timestamp greater than or equal to current. """ yield NotificationManager.NotifyUploadContacts(self._client, self._user_id, self._notify_timestamp)
def _NotifyOneViewpoint(notify_viewpoint_id): """Notify all followers of a single viewpoint of the unshare.""" # Add viewpoint_id to activity_id for unshares from derived viewpoints. This ensures that # the activity_id is globally unique, which the client requires. It also preserves the # guarantee of idempotency, since the viewpoint_id will always be the same no matter how # many times this unshare operation is executed. if notify_viewpoint_id != self._viewpoint_id: # Override the activity_id attribute in "activity". act_dict = deepcopy(self._activity) act_dict['activity_id'] = Activity.ConstructActivityId( truncated_ts, device_id, (client_id, notify_viewpoint_id)) else: act_dict = self._activity notify_ep_dicts = [ { 'episode_id': episode_id, 'photo_ids': photo_ids } for episode_id, photo_ids in self._unshares_dict[notify_viewpoint_id].iteritems() ] yield NotificationManager.NotifyUnshare( self._client, notify_viewpoint_id, self._vp_followers_dict[notify_viewpoint_id][1], act_dict, notify_ep_dicts, notify_viewpoint_id in self._cover_photo_set)
def _Notify(self): """Creates notifications: 1. Notifies removed followers that conversation has new activity. 2. Notifies existing followers of the viewpoint that a new comment has been added. """ # Creates notifications for any revived followers. yield NotificationManager.NotifyReviveFollowers(self._client, self._viewpoint_id, self._revive_follower_ids, self._op.timestamp) # Notifies followers that a comment has been added. yield NotificationManager.NotifyPostComment(self._client, self._followers, self._act_dict, self._cm_dict)
def TerminateAccountOperation(cls, client, user_id, merged_with=None): """Invokes User.TerminateAccount via operation execution.""" @gen.coroutine def _VisitIdentity(identity_key): """Unlink this identity from the user.""" yield Identity.UnlinkIdentityOperation(client, user_id, identity_key.hash_key) # Turn off alerts to all devices owned by the user. yield gen.Task(Device.MuteAlerts, client, user_id) # Unlink every identity attached to the user. query_expr = ('identity.user_id={id}', {'id': user_id}) yield gen.Task(Identity.VisitIndexKeys, client, query_expr, _VisitIdentity) # Add an analytics entry for this user. timestamp = Operation.GetCurrent().timestamp payload = 'terminate' if merged_with is None else 'merge=%s' % merged_with analytics = Analytics.Create(entity='us:%d' % user_id, type=Analytics.USER_TERMINATE, timestamp=timestamp, payload=payload) yield gen.Task(analytics.Update, client) # Terminate the user account. yield gen.Task(User.TerminateAccount, client, user_id, merged_with=merged_with) # Notify all friends that this user account has been terminated. yield NotificationManager.NotifyTerminateAccount(client, user_id)
def _Notify(self): """Creates notifications: 1. Notify all of the user's devices that photos have been hidden. """ yield NotificationManager.NotifyHidePhotos(self._client, self._user.user_id, self._ep_dicts)
def UpdateOperation(cls, client, callback, user_dict, settings_dict): """Invokes User.Update via operation execution.""" yield gen.Task(User.UpdateWithSettings, client, user_dict, settings_dict) timestamp = Operation.GetCurrent().timestamp yield NotificationManager.NotifyUpdateUser(client, user_dict, settings_dict, timestamp) callback()
def _Notify(self): """Creates notification: Notify of all contacts with timestamp greater than or equal to current. May also indicate that all 'removed' contacts have been deleted and the client should reset by reloading all contacts. """ yield NotificationManager.NotifyFetchContacts( self._client, self._user_id, self._notify_timestamp, self._removed_contacts_reset)
def UpdateOperation(cls, client, callback, user_id, friend): """Updates friend metadata for the relationship between the given user and friend.""" # Update the metadata. yield gen.Task(Friend.MakeFriendAndUpdate, client, user_id, friend) # Send notifications to all the calling user's devices. yield NotificationManager.NotifyUpdateFriend(client, friend) callback()
def _Notify(self): """Creates notifications: 1. Notifies existing followers of the viewpoint that followers have been removed. 2. Notifies removed followers that they have been removed from the viewpoint. """ # Creates notifications for removal of followers of the viewpoint. yield NotificationManager.NotifyRemoveFollowers( self._client, self._viewpoint_id, self._followers, self._remove_ids, self._act_dict)
def UnlinkIdentityOperation(cls, client, user_id, identity): """Unlinks the specified identity from any associated viewfinder user.""" # All contacts created during UnlinkIdentity are based on the current operation's timestamp. timestamp = Operation.GetCurrent().timestamp yield Identity.UnlinkIdentity(client, user_id, identity, timestamp) # Notify clients of any contacts that have been updated. yield NotificationManager.NotifyUnlinkIdentity(client, user_id, identity, timestamp)
def _Notify(self): """Creates notifications: 1. Notifies other users with contacts that are bound to the identity. 2. Notifies target user that identities have changed. """ # Send notifications for all identities that were re-bound. yield NotificationManager.NotifyLinkIdentity(self._client, self._target_user_id, self._source_identity_key, self._op.timestamp)
def _Notify(self): """Creates notifications: 1. Notifies all devices of the default viewpoint owner that new photos have been saved. """ follower = yield gen.Task(Follower.Query, self._client, self._user.user_id, self._user.private_vp_id, None) yield NotificationManager.NotifySavePhotos(self._client, self._user.private_vp_id, follower, self._act_dict, self._save_ep_dicts)
def _Validate(follower_id, viewpoint_id, last_updated): sort_key = Followed.CreateSortKey(viewpoint_id, last_updated) self._validator.ValidateCreateDBObject(Followed, user_id=follower_id, sort_key=sort_key, date_updated=Followed._TruncateToDay(last_updated), viewpoint_id=viewpoint_id) invalidate = NotificationManager._CreateViewpointInvalidation(viewpoint_id) self._validator.ValidateNotification('dbchk add_followed', follower_id, self._op_dict, invalidate)
def _Notify(self): """Creates notifications: 1. Notify all of the user's devices that the follower has been updated. """ yield NotificationManager.NotifyUpdateFollower(self._client, self._foll_dict)
def _OnRecord(): NotificationManager.NotifyRecordSubscription(client, user_id, callback=callback)
def _Notify(self): """Creates notifications: 1. Notify all of the user's devices that the viewpoint has been removed for them. """ yield NotificationManager.NotifyRemoveViewpoint( self._client, self._user_id, self._viewpoint_id)
def _MergeOneViewpoint(self, viewpoint_id): """Adds the target user as a follower of the given viewpoint owned by the source user. Accumulates the size of all viewpoints that are merged. Creates notifications for the merged viewpoint. Sets a checkpoint containing follower and accounting information to be used if a restart occurs. """ # Skip default and system viewpoints. viewpoint = yield gen.Task(Viewpoint.Query, self._client, viewpoint_id, None) if viewpoint.IsDefault() or viewpoint.IsSystem(): return # Lock the viewpoint while querying and modifying to the viewpoint. vp_lock = yield gen.Task(Viewpoint.AcquireLock, self._client, viewpoint_id) try: if self._op.checkpoint is None: # Get list of existing followers. existing_follower_ids, _ = yield gen.Task(Viewpoint.QueryFollowerIds, self._client, viewpoint_id, limit=Viewpoint.MAX_FOLLOWERS) # Skip viewpoint if target user is already a follower. if self._target_user_id in existing_follower_ids: return # Skip viewpoint if there are too many followers (this should virtually never happen, since client # enforces an even smaller limit). if len(existing_follower_ids) >= Viewpoint.MAX_FOLLOWERS: logging.warning('merge of user %d into user %d would exceed follower limit on viewpoint "%s"', (self._source_user_id, self._target_user_id, viewpoint_id)) return # Add size of this viewpoint to the accounting accumulator and checkpoint in case operation restarts. yield self._acc_accum.MergeAccounts(self._client, viewpoint_id, self._target_user_id) checkpoint = {'state': 'vp', 'id': viewpoint_id, 'existing': existing_follower_ids, 'account': self._acc_accum.GetUserVisibleTo(self._target_user_id)._asdict()} yield self._op.SetCheckpoint(self._client, checkpoint) else: # Re-constitute state from checkpoint. existing_follower_ids = self._op.checkpoint['existing'] accounting = Accounting.CreateFromKeywords(**self._op.checkpoint['account']) self._acc_accum.GetUserVisibleTo(self._target_user_id).IncrementStatsFrom(accounting) # Get the source follower. source_follower = yield gen.Task(Follower.Query, self._client, self._source_user_id, viewpoint_id, None) # Now actually add the target user as a follower. target_follower = (yield viewpoint.AddFollowers(self._client, source_follower.adding_user_id, existing_follower_ids, [self._target_user_id], self._op.timestamp))[0] # Get list of existing follower db objects. follower_keys = [DBKey(follower_id, viewpoint_id) for follower_id in existing_follower_ids] existing_followers = yield gen.Task(Follower.BatchQuery, self._client, follower_keys, None) # Synthesize a unique activity id by adding viewpoint id to the activity id. truncated_ts, device_id, (client_id, server_id) = Activity.DeconstructActivityId(self._act_dict['activity_id']) activity_id = Activity.ConstructActivityId(truncated_ts, device_id, (client_id, viewpoint_id)) activity_dict = {'activity_id': activity_id, 'timestamp': self._act_dict['timestamp']} # Create merge-related notifications. yield NotificationManager.NotifyMergeViewpoint(self._client, viewpoint_id, existing_followers, target_follower, self._source_user_id, activity_dict, self._op.timestamp) finally: yield gen.Task(Viewpoint.ReleaseLock, self._client, viewpoint_id, vp_lock)