#NEWLINE# @ gen . engine #NEWLINE# def SelectCoverPhoto( self , client , exclude_posts_set , callback , activities_list = None , available_posts_dict = None ) : #NEWLINE# #INDENT# "Select a cover photo for this viewpoint.\n    This is used to select a cover photo if the current cover photo gets unshared.\n    The selection order here assumes that the order of episodes and photos in the\n    activities reflects the intended order of selection.  This won't be true\n    of activities created before this change goes into production, but we've\n    decided to accept this small variation in cover photo selection for these\n    older activities because we don't think it's worth the extra complexity that it\n    would take to make selection of those more 'correct'.\n    Newer clients should order episodes and photos within share requests according to\n    cover photo selection priority.\n    Although older clients provide un-ordered lists of episodes/photos, a request transform\n    will order episodes/photos from those clients using the original mobile client\n    algorithm for cover photo selection. So we will select a new cover photo\n    assuming these activities are already ordered.\n    Caller may supply list of activities to use so that querying them for the viewpoint isn't needed.\n    Caller may supply dict of available (not Removed/Unshared) posts so querying for posts isn't needed.\n    Search process:\n    1) oldest to newest activity (share_new or share_existing activities).\n    2) within activity, first to last episode.\n    3) within episode, first to last photo.\n    Only photos which aren't unshared qualify.\n    Returns: cover_photo dict of selected photo or None if one if no selection is found.\n    " #NEWLINE# from viewfinder.backend.db.post import Post #NEWLINE# batch_limit = 50 #NEWLINE# assert ( not self . IsDefault ( ) ) , self #NEWLINE# @ gen . coroutine #NEWLINE# def _QueryAvailablePost( episode_id , photo_id ) : #NEWLINE# #INDENT# if ( available_posts_dict is not None ) : #NEWLINE# #INDENT# post = available_posts_dict . get ( Post . ConstructPostId ( episode_id , photo_id ) , None ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# post = ( yield gen . Task ( Post . Query , client , episode_id , photo_id , col_names = None ) ) #NEWLINE# if post . IsRemoved ( ) : #NEWLINE# #INDENT# post = None #NEWLINE# #UNINDENT# #UNINDENT# raise gen . Return ( post ) #NEWLINE# #UNINDENT# excl_start_key = None #NEWLINE# while True : #NEWLINE# #INDENT# if ( activities_list is None ) : #NEWLINE# #INDENT# activities = ( yield gen . Task ( Activity . RangeQuery , client , self . viewpoint_id , range_desc = None , limit = callback , col_names = None , excl_start_key = excl_start_key , scan_forward = False ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# activities = activities_list #NEWLINE# #UNINDENT# for activity in activities : #NEWLINE# #INDENT# if ( ( activity . name == 'share_new' ) or ( activity . name == 'share_existing' ) ) : #NEWLINE# #INDENT# args_dict = json . loads ( activity . json ) #NEWLINE# for ep_dict in args_dict [ 'episodes' ] : #NEWLINE# #INDENT# episode_id = ep_dict [ 'episode_id' ] #NEWLINE# for photo_id in ep_dict [ 'photo_ids' ] : #NEWLINE# #INDENT# if ( ( episode_id , photo_id ) not in exclude_posts_set ) : #NEWLINE# #INDENT# post = ( yield _QueryAvailablePost ( episode_id , photo_id ) ) #NEWLINE# if ( post is not None ) : #NEWLINE# #INDENT# callback ( Viewpoint . ConstructCoverPhoto ( episode_id , photo_id ) ) #NEWLINE# return #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# if ( ( activities_list is not None ) or ( len ( activities ) < batch_limit ) ) : #NEWLINE# #INDENT# break #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# excl_start_key = activities [ ( - 1 ) ] . GetKey ( ) #NEWLINE# #UNINDENT# #UNINDENT# callback ( None )