<s> """<STR_LIT>""" <EOL> __authors__ = [ '<STR_LIT>' ] <EOL> import json <EOL> from tornado import gen <EOL> from viewfinder . backend . base . exceptions import LimitExceededError , PermissionError <EOL> from viewfinder . backend . db . accounting import AccountingAccumulator <EOL> from viewfinder . backend . db . db_client import DBKey <EOL> from viewfinder . backend . db . followed import Followed <EOL> from viewfinder . backend . db . follower import Follower <EOL> from viewfinder . backend . db . lock import Lock <EOL> from viewfinder . backend . db . operation import Operation <EOL> from viewfinder . backend . db . user import User <EOL> from viewfinder . backend . db . viewpoint import Viewpoint <EOL> from viewfinder . backend . op . notification_manager import NotificationManager <EOL> from viewfinder . backend . op . viewfinder_op import ViewfinderOperation <EOL> class AddFollowersOperation ( ViewfinderOperation ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , client , act_dict , user_id , viewpoint_id , contact_dicts ) : <EOL> super ( AddFollowersOperation , self ) . __init__ ( client ) <EOL> self . _act_dict = act_dict <EOL> self . _user_id = user_id <EOL> self . _viewpoint_id = viewpoint_id <EOL> self . _contact_dicts = contact_dicts <EOL> @ classmethod <EOL> @ gen . coroutine <EOL> def Execute ( cls , client , activity , user_id , viewpoint_id , contacts ) : <EOL> """<STR_LIT>""" <EOL> yield AddFollowersOperation ( client , activity , user_id , viewpoint_id , contacts ) . _AddFollowers ( ) <EOL> @ gen . coroutine <EOL> def _AddFollowers ( self ) : <EOL> """<STR_LIT>""" <EOL> lock = yield gen . Task ( Viewpoint . AcquireLock , self . _client , self . _viewpoint_id ) <EOL> try : <EOL> yield self . _Check ( ) <EOL> self . _client . CheckDBNotModified ( ) <EOL> yield self . _Update ( ) <EOL> yield self . _Account ( ) <EOL> yield Operation . TriggerFailpoint ( self . _client ) <EOL> yield self . _Notify ( ) <EOL> finally : <EOL> yield gen . Task ( Viewpoint . ReleaseLock , self . _client , self . _viewpoint_id , lock ) <EOL> @ gen . coroutine <EOL> def _Check ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _viewpoint , self . _follower = yield gen . Task ( Viewpoint . QueryWithFollower , <EOL> self . _client , <EOL> self . _user_id , <EOL> self . _viewpoint_id ) <EOL> if self . _follower is None or not self . _follower . CanContribute ( ) : <EOL> raise PermissionError ( '<STR_LIT>' % <EOL> ( self . _user_id , self . _viewpoint_id ) ) <EOL> if self . _op . checkpoint is None : <EOL> self . _existing_followers , _ = yield gen . Task ( Viewpoint . QueryFollowers , <EOL> self . _client , <EOL> self . _viewpoint_id , <EOL> limit = Viewpoint . MAX_FOLLOWERS ) <EOL> self . _revive_follower_ids = self . _GetRevivableFollowers ( self . _existing_followers ) <EOL> self . _contact_ids = yield self . _ResolveContactIds ( self . _contact_dicts ) <EOL> checkpoint = { '<STR_LIT>' : [ follower . user_id for follower in self . _existing_followers ] , <EOL> '<STR_LIT>' : self . _revive_follower_ids , <EOL> '<STR_LIT>' : self . _contact_ids } <EOL> yield self . _op . SetCheckpoint ( self . _client , checkpoint ) <EOL> else : <EOL> follower_keys = [ DBKey ( follower_id , self . _viewpoint_id ) for follower_id in self . _op . checkpoint [ '<STR_LIT>' ] ] <EOL> self . _existing_followers = yield gen . Task ( Follower . BatchQuery , self . _client , follower_keys , None ) <EOL> self . _revive_follower_ids = self . _op . checkpoint [ '<STR_LIT>' ] <EOL> self . _contact_ids = self . _op . checkpoint [ '<STR_LIT>' ] <EOL> self . _contact_user_ids = [ user_id for user_exists , user_id , webapp_dev_id in self . _contact_ids ] <EOL> if len ( self . _existing_followers ) + len ( self . _contact_dicts ) > Viewpoint . MAX_FOLLOWERS : <EOL> raise LimitExceededError ( <EOL> '<STR_LIT>' % <EOL> ( self . _user_id , self . _viewpoint_id , len ( self . _contact_dicts ) ) ) <EOL> @ gen . coroutine <EOL> def _Update ( self ) : <EOL> """<STR_LIT>""" <EOL> yield self . _ResolveContacts ( self . _contact_dicts , self . _contact_ids , reason = '<STR_LIT>' % self . _user_id ) <EOL> yield gen . Task ( Follower . ReviveRemovedFollowers , self . _client , self . _existing_followers ) <EOL> existing_follower_ids = set ( follower . user_id for follower in self . _existing_followers <EOL> if not follower . IsRemoved ( ) ) <EOL> self . _new_follower_ids = [ user_id for user_id in set ( self . _contact_user_ids ) <EOL> if user_id not in existing_follower_ids ] <EOL> self . _new_followers = yield self . _viewpoint . AddFollowers ( self . _client , <EOL> self . _user_id , <EOL> list ( existing_follower_ids ) , <EOL> self . _new_follower_ids , <EOL> self . _op . timestamp ) <EOL> @ gen . coroutine <EOL> def _Account ( self ) : <EOL> """<STR_LIT>""" <EOL> acc_accum = AccountingAccumulator ( ) <EOL> yield acc_accum . ReviveFollowers ( self . _client , self . _viewpoint_id , self . _revive_follower_ids ) <EOL> yield acc_accum . AddFollowers ( self . _client , self . _viewpoint_id , self . _new_follower_ids ) <EOL> yield acc_accum . Apply ( self . _client ) <EOL> @ gen . coroutine <EOL> def _Notify ( self ) : <EOL> """<STR_LIT>""" <EOL> identity_keys = [ contact_dict [ '<STR_LIT>' ] <EOL> for contact_dict , ( user_exists , user_id , webapp_dev_id ) in zip ( self . _contact_dicts , <EOL> self . _contact_ids ) <EOL> if not user_exists ] <EOL> yield NotificationManager . NotifyCreateProspective ( self . _client , <EOL> identity_keys , <EOL> self . _op . timestamp ) <EOL> yield NotificationManager . NotifyReviveFollowers ( self . _client , <EOL> self . _viewpoint_id , <EOL> self . _revive_follower_ids , <EOL> self . _op . timestamp ) <EOL> yield NotificationManager . NotifyAddFollowers ( self . _client , <EOL> self . _viewpoint_id , <EOL> self . _existing_followers , <EOL> self . _new_followers , <EOL> self . _contact_user_ids , <EOL> self . _act_dict , <EOL> self . _op . timestamp ) </s>
