def set_gid_shorten_urls(self, gid, shorten): if shorten: self.set_destination_param(gid, 'cache', '', S1.cache_shorten_urls(), shorten) else: self.del_destination_param(gid, 'cache', '', S1.cache_shorten_urls())
def set_provider_session(self, gid, session_id, provider, data): """ Use to store arbitrary session data specific to a provider. All session for all providers is cleared when user logs off """ self.rc.hset(S1.gid_key(gid), S1.destination_session_id_fmt(provider, session_id), json.dumps(data))
def flush_updates(self, gid): """ flushes any updates stuck in the update queue """ destinations = self.get_destinations(gid) self.logger.info('Notifying destinations: {0}'.format(destinations)) for destination in destinations: self.pubsub.broadcast_command( S1.publisher_channel_name(destination), S1.msg_publish(), gid)
def purge_gid_links(self, destination, user): """ cleans abandoned account links """ # find all parents' [p]->destination:user # find all gids that feed the [p]->[destination:user] <- [gid] # if the gid is not in gids -- break the link parent -> gid # iterate over list of owners/parents of this destination:user account parents = self.get_linked_parents(S1.provider_root_key( destination, user), bag='dst') for parent in parents: # purge gid 2 gid links # this is now a manual process -- users can remove gid-gid links from the UI # self._purge_gid_gid(parent, gid) # check if destination:user is being fed by any of the parent's children # Note: parent will be listed as child of self children = self.get_linked_children(parent) child_links = set(self.get_bindings(destination, user)) if not len(child_links.intersection(children)): self.logger.info( 'Removing account linking: [{0}] --> [{1}]'.format( parent, S1.provider_root_key(destination, user))) self.remove_linked_account(parent, S1.provider_root_key( destination, user), bag='dst')
def del_provider_session(self, gid, provider): keys = self.rc.hkeys(S1.gid_key(gid)) to_clear = [ key for key in keys if key.startswith(S1.destination_session_fmt(provider)) ] if len(to_clear): self.rc.hdel(S1.gid_key(gid), *to_clear)
def add_linked_account(self, parent_gid, gid, bag=None): parent_key = S1.provider_root_key('parents', bag) if bag else 'parents' child_key = S1.provider_root_key('children', bag) if bag else 'children' self._append_hfield(S1.destination_key_fmt(parent_key), gid, parent_gid) self._append_hfield(S1.destination_key_fmt(child_key), parent_gid, gid)
def bind_destination(self, gid, destination, user): # bind source and destination self._append_hfield(S1.destination_key_fmt(destination), gid, user) # bind destination to source self._append_hfield(S1.destination_source_key_fmt(destination), user, gid) # append destination list for the source self._append_hfield(S1.destination_key_fmt(S1.destinations_key()), gid, destination)
def remove_linked_account(self, parent_gid, gid, bag=None): parent_key = S1.provider_root_key('parents', bag) if bag else 'parents' child_key = S1.provider_root_key('children', bag) if bag else 'children' self._delete_hfield_item(S1.destination_key_fmt(parent_key), gid, parent_gid) self._delete_hfield_item(S1.destination_key_fmt(child_key), parent_gid, gid)
def remove_from_poller(self, gid): # remove from master set self.rc.zrem(S1.gid_set('all'), gid) # clear cache self.rc.delete(S1.cache_key(gid)) self.del_destination_param(gid, 'cache', gid, S1.updated_key()) self.del_destination_param(gid, 'cache', gid, S1.etag_key()) self.purge_temp_accounts(gid)
def purge_temp_accounts(self, gid): # remove all accounts links_t = self.rc.smembers(S1.links_temp_key(gid)) links = links_t.difference(self.rc.smembers(S1.links_key(gid))) for link in links: # second check for usage in another account if self.rc.hexists(S1.destination_key_fmt('parents:dst'), link): continue self.rc.hdel(link, S1.ACCOUNT_KEY) self.rc.delete(S1.links_temp_key(gid))
def add_log(self, gid, message): # log to log file self.logger.error('User Log [{0}]: {1}'.format(gid, message)) # log to gid's log if key does not exist if self.rc.zscore(S1.gid_log_key(gid), message): return # add new record self.rc.zadd(S1.gid_log_key(gid), message, time.time()) # trim log to latest 99 messages self.rc.zremrangebyrank(S1.gid_log_key(gid), 0, -100)
def get_destination_first_use(self, gid, destination, user): """ returns first use timestamp for destination """ result = self.get_destination_param(gid, destination, user, S1.bound_key()) if not result: return 0 return float(result)
def bind_user(self, master_gid, gid, destination, user): # bind to destination poller self.logger.info('Binding: [{0}] --> [{1}]:[{2}]'.format( gid, destination, user)) # store gid to gid relation self.add_linked_account(master_gid, gid) # store gid to destination user relation self.add_linked_account(master_gid, S1.provider_root_key(destination, user), bag='dst') # reset timestamps and errors self.reset_destination(gid, destination, user) # bind source and destination self.bind_destination(gid, destination, user) # carpet-notify GID destinations of updates self.flush_updates(gid) # append GID log self.add_log( master_gid, 'Success: Linked Google+ [{0}] --> [{1}:{2}]'.format( gid, destination, user)) self.logger.info('Success: Linked Google+ [{0}] --> [{1}:{2}]'.format( gid, destination, user))
def get_destination_update(self, gid, destination, user): """ returns last update timestamp for destination """ result = self.get_destination_param(gid, destination, user, S1.updated_key()) if not result: return 0 return float(result)
def remove_binding(self, gid, destination, user, clean=False): """ clears binding created by bind_user() """ self.logger.info('Unbinding GID: [{0}] -/-> [{1}:{2}]'.format( gid, destination, user)) self.add_log( gid, 'Unbinding Google+ [{0}] -/-> [{1}:{2}]'.format( gid, destination, user)) # remove binding update option self.rc.hdel(S1.destination_option_key_fmt(destination), S1.destination_pair_fmt(gid, user, S1.updated_key())) # remove destination user id from list of destinations for this gid self._delete_hfield_item(S1.destination_key_fmt(destination), gid, user) # remove gid from list of sources for this destination user self._delete_hfield_item(S1.destination_source_key_fmt(destination), user, gid) # clean linked accounts # find the owner(s) of the destination:user pair self.purge_gid_links(destination, user) # the gid->destination:user link is broken # clear this relationship self.remove_linked_account(gid, S1.provider_root_key(destination, user), bag='dst') # remove destination binding if no bindings to this destination left bound_users = self.get_destination_users(gid, destination) if not (bound_users and len(bound_users)): self.logger.info('No links remain for [{0} --> {1}]'.format( gid, destination)) # remove destination from gid destination list self._delete_hfield_item( S1.destination_key_fmt(S1.destinations_key()), gid, destination) # keep message map for the destination:user -- user may re-bind later with new token # unless forced to clean all # keep filters unless forced to clean! if clean: self.filter.del_filter(destination, gid, user) self.filter.del_message_id_map(destination, user) # clear bound timestamp self.del_destination_param(gid, destination, user, S1.bound_key()) # check_orphan() will stop polling the gid if nothing is bound to it self.check_orphan(gid, 0)
def end_service_query(self, gid, query): # get all in list results = self.rc.lrange(S1.query_list_out(query), 0, -1) if not results: return None received = [] # check all results for the specified gid mask = '{0}:'.format(gid) for result in results: if result.startswith(mask): self.rc.lrem(S1.query_list_out(query), result) # filter out empty results received.append(result[len(mask):]) return [r for r in received if r] if len(received) else None
def get_log(self, gid): # get child account logs too children = set(self.get_destination_users(gid, 'children')) children.add(gid) log = { k: self.rc.zrange(S1.gid_log_key(k), 0, -1, withscores=True) for k in children } return log
def get_linked_users(self, gid, destination, user): """ yields a list of user gids who own gid->destination:user binding @param gid: gid of the source, not user gid @param destination: name of the destination i.e. "facebook" @param user: destination user id @return: yeilds gids of users who own gid->destination:user binding """ parents = self.get_linked_parents(gid) for parent in parents: children = self.get_linked_children(parent, bag='dst') if S1.provider_root_key(destination, user) in children: yield parent
def forget_source(self, master_gid, gid): """ Removes source gid, unlinks all bindings associated with the source @param master_gid: master gid @param gid: source gid @return: """ self.logger.info('Removing source [{0}:{1}]...'.format( master_gid, gid)) destinations = self.get_destinations(gid) for destination in destinations: users = self.get_destination_users(gid, destination) for user in users: # source gid can be bound to destination that does not belong to this master gid # forget_destination will only remove bindings that belong to this master gid DataApi.forget_destination(self, self.logger, gid, destination, user) # remove the gid from the list of child accounts self.remove_linked_account(master_gid, gid) # clear gid data if no destinations left destinations = self.get_destinations(gid) if not destinations: self.logger.info( 'Source [{0}:{1}] is orphaned, cleaning...'.format( master_gid, gid)) # remove user keys self.rc.delete(S1.gid_key(gid)) self.rc.delete(S1.gid_log_key(gid)) self.rc.delete(S1.links_key(gid)) self.rc.delete(S1.cache_key(gid)) self.del_destination_param(gid, 'cache', '', S1.cache_shorten_urls()) # clear chache and remove gid from poller list self.remove_from_poller(gid) # remove tnc self.rc.hdel(S1.TERMS_OK_KEY, gid)
def is_valid_gid(self, gid): return self.rc.zscore(S1.gid_set('all'), gid) or self.rc.exists( S1.gid_key(gid))
def get_provider_session(self, gid, session_id, provider): value = self.rc.hget( S1.gid_key(gid), S1.destination_session_id_fmt(provider, session_id)) return json.loads(value) if value else None
def get_gid_shorten_urls(self, gid): return self.get_destination_param(gid, 'cache', '', S1.cache_shorten_urls())
def refresh_user_token(self, gid, provider, pid): self.pubsub.broadcast_command(S1.publisher_channel_name(provider), S1.msg_register(), pid)
def set_limits(self, gid, limit_tag): if limit_tag: self.rc.hset(S1.gid_key(gid), S1.LIMITS_KEY, limit_tag) else: self.rc.hdel(S1.gid_key(gid), S1.LIMITS_KEY)
def add_temp_account(self, gid, provider, user, data): self.rc.sadd(S1.links_temp_key(gid), S1.provider_root_key(provider, user)) self.rc.hset(S1.provider_root_key(provider, user), S1.ACCOUNT_KEY, data)
def get_limits(self, gid): return self.rc.hget(S1.gid_key(gid), S1.LIMITS_KEY)
def del_log(self, gid): self.rc.delete(S1.gid_log_key(gid))
def is_linked_account(self, gid, provider, user): return self.rc.sismember(S1.links_key(gid), S1.provider_root_key(provider, user))
def set_provider_error_count(self, provider, user, count): self.rc.hset(S1.provider_root_key(provider, user), S1.error_count_key(), count)
def get_provider_error_count(self, provider, user): count_str = self.rc.hget(S1.provider_root_key(provider, user), S1.error_count_key()) return int(count_str) if count_str else 0