def _add_follows(self, followiterator, key): ''' Guarda el usuario en el ultimo index posible, si se ha llegado al maximo numero de usuarios por lista, se crea uno nuevo. :param followiterator: Iterador con la consulta para obtener los index, ordenador por fecha de creacion asi el primero de la lista, sera el ultimo index posible. :type followiterator: :class:`_QueryIterator` :param key: key del usuario a añadir :type key: :class:`db.Key() :returns: True si se añadio el usuario ''' from models_acc import UserFollowingIndex try: last_follow = followiterator.next() # como estan ordenados por fecha de creacion, carga el primero que seria el ultimo indice. except StopIteration: last_follow = UserFollowingIndex(parent=self) if len(last_follow.following) < TIMELINE_PAGE_SIZE*2: # un maximo de usuarios en este index para que las listas no sean lentas last_follow.following.append(key) else: # creamos un index nuevo last_follow = UserFollowingIndex(parent=self, following=[key]) try: from models_acc import UserCounter counter_result = self.counters_async() # obtiene los contadores de self follow_query = UserCounter.all().ancestor(key) # obtiene los contadores del otro usuario follow_result = follow_query.run() counter_result = counter_result.next() follow_result = follow_result.next() counter_result.set_followings(+1) # sumamos uno al contador de following follow_result.set_followers(+1)# sumamos uno al contador de followers del otro usuario except: return False last_follow.put() return True
def has_follower(self, user=None, userkey=None): from models_acc import UserFollowingIndex if userkey is not None: if UserFollowingIndex.all(keys_only=True).ancestor(userkey).filter('following =', self.key()).get() is not None: return True elif not user.is_authenticated(): return False elif UserFollowingIndex.all(keys_only=True).ancestor(user.key()).filter('following =', self.key()).get() is not None: return True return False
def has_follower(self, user=None, userkey=None): from models_acc import UserFollowingIndex if userkey is not None: if UserFollowingIndex.all(keys_only=True).ancestor(userkey).filter( 'following =', self.key()).get() is not None: return True elif not user.is_authenticated(): return False elif UserFollowingIndex.all(keys_only=True).ancestor( user.key()).filter('following =', self.key()).get() is not None: return True return False
def _del_follows(self, key): ''' Borra un key de la lista de following :param key: key del usuario a borrar :type key: :class:`db.Key() :returns: True si se borro el usuario, False si no se encontro ''' from models_acc import UserFollowingIndex index = UserFollowingIndex.all().ancestor(self.key()).filter( 'following =', key).get() if index is not None: index.following.remove(key) try: from models_acc import UserCounter counter_result = self.counters_async( ) # obtiene los contadores de self follow_query = UserCounter.all().ancestor( key) # obtiene los contadores del otro usuario follow_result = follow_query.run() counter_result = counter_result.next() follow_result = follow_result.next() counter_result.set_followings( -1) # sumamos uno al contador de following follow_result.set_followers( -1 ) # sumamos uno al contador de followers del otro usuario except: return False index.put() return True return False
def _del_follows(self, key): ''' Borra un key de la lista de following :param key: key del usuario a borrar :type key: :class:`db.Key() :returns: True si se borro el usuario, False si no se encontro ''' from models_acc import UserFollowingIndex index = UserFollowingIndex.all().ancestor(self.key()).filter('following =', key).get() if index is not None: index.following.remove(key) try: from models_acc import UserCounter counter_result = self.counters_async() # obtiene los contadores de self follow_query = UserCounter.all().ancestor(key) # obtiene los contadores del otro usuario follow_result = follow_query.run() counter_result = counter_result.next() follow_result = follow_result.next() counter_result.set_followings(-1) # sumamos uno al contador de following follow_result.set_followers(-1) # sumamos uno al contador de followers del otro usuario except: return False index.put() return True return False
def get_followings(self, userid=None, username=None, page=1, query_id=None): """Obtiene la lista de personas a las que sigue el usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] :raises: AttributeError """ if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) else: raise AttributeError() from georemindme.paging import PagedQuery from models_acc import UserFollowingIndex followings = UserFollowingIndex.all().ancestor(userkey).order("-created") p = PagedQuery(followings, id=query_id) users = [index.following for index in p.fetch_page(page)] # devuelve una lista anidada con otra users = db.get([item for sublist in users for item in sublist]) return [p.id, [{"id": u.id, "username": u.username, "profile": u.profile} for u in users]]
def are_friends(self, friend): from models_acc import UserFollowingIndex if isinstance(friend, db.Key): user_following = UserFollowingIndex.all().filter('following =', friend).ancestor(self.key()).count() if user_following == 0: return False friend_following = UserFollowingIndex.all().filter('following =', self.key()).ancestor(friend).count() if friend_following == 0: return False else: user_following = UserFollowingIndex.all().filter('following =', friend.key()).ancestor(self.key()).count() if user_following == 0: return False friend_following = UserFollowingIndex.all().filter('following =', self.key()).ancestor(friend.key()).count() if friend_following == 0: return False return True
def are_friends(self, friend): from models_acc import UserFollowingIndex if isinstance(friend, db.Key): user_following = UserFollowingIndex.all().filter( 'following =', friend).ancestor(self.key()).count() if user_following == 0: return False friend_following = UserFollowingIndex.all().filter( 'following =', self.key()).ancestor(friend).count() if friend_following == 0: return False else: user_following = UserFollowingIndex.all().filter( 'following =', friend.key()).ancestor(self.key()).count() if user_following == 0: return False friend_following = UserFollowingIndex.all().filter( 'following =', self.key()).ancestor(friend.key()).count() if friend_following == 0: return False return True
def get_friends(self): from models_acc import UserFollowingIndex indexes = UserFollowingIndex.all().ancestor(self.key()) # cargo la lista completa de todos a los que sigue el usuario followings = [] followings.extend([following for index in indexes for following in index.following]) friends = [] for follow in followings: key = db.GqlQuery('SELECT __key__ FROM UserFollowingIndex WHERE ANCESTOR IS :1 AND following =:2', follow, self.key()).get() if key is not None: friends.append(follow) return db.get_async(friends)
def get_friends(self): from models_acc import UserFollowingIndex indexes = UserFollowingIndex.all().ancestor(self.key()) # cargo la lista completa de todos a los que sigue el usuario followings = [] followings.extend( [following for index in indexes for following in index.following]) friends = [] for follow in followings: key = db.GqlQuery( 'SELECT __key__ FROM UserFollowingIndex WHERE ANCESTOR IS :1 AND following =:2', follow, self.key()).get() if key is not None: friends.append(follow) return db.get_async(friends)
def _tx(user): try: from models_acc import UserFollowingIndex, UserSettings, UserProfile, UserCounter settings = UserSettings(key_name='settings_%s' % user.id, parent=user, language=language) profile = UserProfile(key_name='profile_%s' % user.id, parent=user, username=user.username, email=user.email) followings = UserFollowingIndex(parent=user) counters = UserCounter(key_name='counters_%s' % user.id, parent=user) db.put_async([settings, profile, followings, counters]) return True except: return False
def add_following(self, followname=None, followid=None): ''' Añade un usuario a la lista de personas que sigue self. El usuario se busca a por username o por id :param followname: El nombre de usuario a seguir :type followname: :class:`string` :param followid: El identificador del usuario a seguir :type followid: :class:`string` ''' if followname is not None: following = User.objects.get_by_username(followname, keys_only=True) elif followid is not None: following = User.objects.get_by_id(followid, keys_only=True) else: raise AttributeError() if following is not None: if following == self.key(): return True # actualiza la cache de amigos sugeridos import memcache friends = memcache.get('%sfriends_to_%s' % (memcache.version, self.key())) if friends is not None and int(following.id()) in friends: del friends[int(following.id())] memcache.set( '%sfriends_to_%s' % (memcache.version, self.key()), friends, 300) # añadimos el seguidor from models_acc import UserFollowingIndex is_following = UserFollowingIndex.all().filter( 'following =', following).ancestor(self.key()).count() if is_following != 0: # en este caso, el usuario ya esta siguiendo al otro, no hacemos nada mas. return True following_result = self.following( async=True) # obtiene un iterador con los UserFollowingIndex if self._add_follows(following_result, following): from signals import user_follower_new user_follower_new.send(sender=self, following=following) return True return False
def get_followers(self, userid=None, username=None, page=1, query_id=None): """Obtiene la lista de followers de un usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] :raises: AttributeError """ if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) else: raise AttributeError() from georemindme.paging import PagedQuery from models_acc import UserFollowingIndex followers = UserFollowingIndex.all().filter("following =", userkey).order("-created") p = PagedQuery(followers, id=query_id) from georemindme.funcs import fetch_parents users = fetch_parents(p.fetch_page(page)) return [ p.id, [ { "id": u.id, "username": u.username, "is_following": u.has_follower(userkey=userkey), "profile": u.profile, } for u in users ], ]
def get_followings(self, userid=None, username=None, page=1, query_id=None): """Obtiene la lista de personas a las que sigue el usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] :raises: AttributeError """ if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) else: raise AttributeError() from georemindme.paging import PagedQuery from models_acc import UserFollowingIndex followings = UserFollowingIndex.all().ancestor(userkey).order( '-created') p = PagedQuery(followings, id=query_id) users = [index.following for index in p.fetch_page(page) ] # devuelve una lista anidada con otra users = db.get([item for sublist in users for item in sublist]) return [ p.id, [{ 'id': u.id, 'username': u.username, 'profile': u.profile } for u in users] ]
def get_followers(self, userid = None, username=None, page=1, query_id=None): ''' Obtiene la lista de followers de un usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] ''' if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) followers = UserFollowingIndex.gql('WHERE following = :1', userkey) p = PagedQuery(followers, id = query_id) ##users = [(u.id, u.username, u.profile.avatar) for u in (index.parent() for index in p.fetch_page(page))] return [p.id, [(u.id, u.username, u.profile.avatar) for u in (index.parent() for index in p.fetch_page(page))]]
def get_followers(self, userid=None, username=None, page=1, query_id=None): """Obtiene la lista de followers de un usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] :raises: AttributeError """ if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) else: raise AttributeError() from georemindme.paging import PagedQuery from models_acc import UserFollowingIndex followers = UserFollowingIndex.all().filter('following =', userkey).order('-created') p = PagedQuery(followers, id=query_id) from georemindme.funcs import fetch_parents users = fetch_parents(p.fetch_page(page)) return [ p.id, [{ 'id': u.id, 'username': u.username, 'is_following': u.has_follower(userkey=userkey), 'profile': u.profile } for u in users] ]
def get_followings(self, userid = None, username=None, page=1, query_id=None): ''' Obtiene la lista de personas a las que sigue el usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param username: nombre del usuario (user.username) :type username: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] ''' if username is not None: userkey = self.get_by_username(username, keys_only=True) elif userid is not None: userkey = db.Key.from_path(User.kind(), userid) followings = UserFollowingIndex.all().ancestor(userkey).order('-created') p = PagedQuery(followings, id = query_id) users = [db.get(index.following) for index in p.fetch_page(page)] # devuelve una lista anidada con otra users = [(item.id, item.username, item.profile.avatar) for sublist in users for item in sublist] # obtenemos las listas anidadas como una sola return [p.id, users]
def add_following(self, followname = None, followid = None): ''' Añade un usuario a la lista de personas que sigue self. El usuario se busca a por username o por id :param followname: El nombre de usuario a seguir :type followname: :class:`string` :param followid: El identificador del usuario a seguir :type followid: :class:`string` ''' if followname is not None: following = User.objects.get_by_username(followname, keys_only=True) elif followid is not None: following = User.objects.get_by_id(followid, keys_only=True) else: raise AttributeError() if following is not None: if following == self.key(): return True # actualiza la cache de amigos sugeridos import memcache friends = memcache.get('%sfriends_to_%s' % (memcache.version, self.key())) if friends is not None and int(following.id()) in friends: del friends[int(following.id())] memcache.set('%sfriends_to_%s' % (memcache.version, self.key()), friends, 300) # añadimos el seguidor from models_acc import UserFollowingIndex is_following = UserFollowingIndex.all().filter('following =', following).ancestor(self.key()).count() if is_following != 0: # en este caso, el usuario ya esta siguiendo al otro, no hacemos nada mas. return True following_result = self.following(async=True) # obtiene un iterador con los UserFollowingIndex if self._add_follows(following_result, following): from signals import user_follower_new user_follower_new.send(sender=self, following=following) return True return False
def _add_follows(self, followiterator, key): ''' Guarda el usuario en el ultimo index posible, si se ha llegado al maximo numero de usuarios por lista, se crea uno nuevo. :param followiterator: Iterador con la consulta para obtener los index, ordenador por fecha de creacion asi el primero de la lista, sera el ultimo index posible. :type followiterator: :class:`_QueryIterator` :param key: key del usuario a añadir :type key: :class:`db.Key() :returns: True si se añadio el usuario ''' from models_acc import UserFollowingIndex try: last_follow = followiterator.next( ) # como estan ordenados por fecha de creacion, carga el primero que seria el ultimo indice. except StopIteration: last_follow = UserFollowingIndex(parent=self) if len( last_follow.following ) < TIMELINE_PAGE_SIZE * 2: # un maximo de usuarios en este index para que las listas no sean lentas last_follow.following.append(key) else: # creamos un index nuevo last_follow = UserFollowingIndex(parent=self, following=[key]) try: from models_acc import UserCounter counter_result = self.counters_async( ) # obtiene los contadores de self follow_query = UserCounter.all().ancestor( key) # obtiene los contadores del otro usuario follow_result = follow_query.run() counter_result = counter_result.next() follow_result = follow_result.next() counter_result.set_followings( +1) # sumamos uno al contador de following follow_result.set_followers( +1) # sumamos uno al contador de followers del otro usuario except: return False last_follow.put() return True
def is_following(self, user): from models_acc import UserFollowingIndex if UserFollowingIndex.all().ancestor(self.key()).filter( 'following =', user.key()).count() != 0: return True return False
def is_following(self, user): from models_acc import UserFollowingIndex if UserFollowingIndex.all().ancestor(self.key()).filter('following =', user.key()).count() != 0: return True return False
class User(polymodel.PolyModel, model_plus.Model): email = db.EmailProperty() username = UsernameProperty() password = PasswordProperty(required=True, indexed=False) confirm_code = db.TextProperty(indexed=False) remind_code = db.TextProperty(indexed=False) date_remind = db.DateTimeProperty(indexed=False) last_point = db.GeoPtProperty(default=db.GeoPt(37.176487, -3.597929), indexed=False) last_address = db.TextProperty(default='', indexed=False) has = db.StringListProperty(default=['active:T', 'confirmed:F', 'admin:F']) created = db.DateTimeProperty(auto_now_add=True, indexed=False) last_login = db.DateTimeProperty(indexed=False) _profile = None _settings = None _google_user = None _twitter_user = None _facebook_user = None _counters = None @classproperty def objects(self): return UserHelper() @property def id(self): return int(self.key().id()) @property def google_user(self, keys_only=False): if self._google_user is None: from models_social import GoogleUser self._google_user = GoogleUser.all(keys_only=keys_only).filter( 'user ='******'user ='******'user ='******'profile_%s' % self.id, parent=self.key()) return self._profile @property def settings(self): if self._settings is None: from models_acc import UserSettings self._settings = UserSettings.get_by_key_name('settings_%s' % self.id, parent=self.key()) return self._settings @property def counters(self): if self._counters is None: from models_acc import UserCounter self._counters = UserCounter.get_by_key_name('counters_%s' % self.id, parent=self.key()) return self._counters def counters_async(self): from models_acc import UserCounter q = UserCounter.all().ancestor(self.key()) return q.run() def get_profile_timeline(self, query_id=None, querier=None): ''' (Wrapper del metodo UserTimeline.objects.get_by_id(...) Obtiene la lista de ultimos timeline publicos del usuario :param userid: id del usuario (user.id) :type userid: :class:`string` :param page: numero de pagina a mostrar :type param: int :param query_id: identificador de busqueda :type query_id: int :returns: lista de tuplas de la forma [query_id, [(id, username, avatar)]] ''' from models_acc import UserTimeline return UserTimeline.objects.get_by_id(self.id, querier=querier, query_id=query_id) def get_activity_timeline(self, query_id=None): from models_acc import UserTimelineSystem, UserTimeline, UserTimelineFollowersIndex, UserTimelineSuggest from geovote.models import Comment, Vote from geoalert.models import Event from geolist.models import List # definir las consultas query_chrono = UserTimelineFollowersIndex.all().filter( 'followers =', self.key()).order('-created') query_activity = UserTimelineSystem.all().filter( 'user ='******'visible =', True).order('-modified') # recuperar cursores if query_id is not None and len(query_id) >= 2: cursor_chronology = query_id[0] cursor_activity = query_id[1] query_chrono = query_chrono.with_cursor( start_cursor=cursor_chronology) query_activity = query_activity.with_cursor( start_cursor=cursor_activity) else: cursor_activity = None cursor_chronology = None # let's go! timeline = [] timeline_chrono = [] activity_async = query_activity.run( config=datastore_query.QueryOptions(limit=TIMELINE_PAGE_SIZE)) chrono_async = query_chrono.run(config=datastore_query.QueryOptions( limit=TIMELINE_PAGE_SIZE)) _go_chrono = True chrono = None for activity_timeline in activity_async: while _go_chrono: if len(timeline) + len(timeline_chrono) >= TIMELINE_PAGE_SIZE: _go_chrono = False break if chrono is None: try: chrono = chrono_async.next() except: _go_chrono = False break if chrono is not None and chrono.created > activity_timeline.modified: timeline_chrono.append(chrono) chrono = None else: break timeline.append(activity_timeline) if len(timeline) + len(timeline_chrono) >= TIMELINE_PAGE_SIZE: break # generar timeline timeline_chrono = fetch_parents(timeline_chrono) timeline = prefetch_refprops(timeline, UserTimeline.user) timeline_chrono = prefetch_refprops(timeline_chrono, UserTimeline.instance, UserTimeline.user) timeline.extend(timeline_chrono) #seguimos cargando por lotes todas las referencias from helpers_acc import _load_ref_instances instances = _load_ref_instances(timeline) timeline = [{ 'id': int(activity_timeline.id), 'created': activity_timeline.created, 'modified': activity_timeline.modified, 'msg': activity_timeline.msg, 'username': activity_timeline.user.username, 'msg_id': activity_timeline.msg_id, 'instance': instances.get( UserTimeline.instance.get_value_for_datastore( activity_timeline), activity_timeline.instance), 'has_voted': Vote.objects.user_has_voted(self, activity_timeline.instance.key()) if activity_timeline.instance is not None else None, 'vote_counter': Vote.objects.get_vote_counter(activity_timeline.instance.key()) if activity_timeline.instance is not None else None, 'comments': Comment.objects.get_by_instance(activity_timeline.instance, querier=self), 'list': instances.get( UserTimelineSuggest.list_id.get_value_for_datastore( activity_timeline), activity_timeline.list_id) if isinstance(activity_timeline, UserTimelineSuggest) else None, 'status': activity_timeline.status if hasattr(activity_timeline, 'status') else None, 'is_private': True, 'user_follower': instances.get( UserTimeline.instance.get_value_for_datastore( activity_timeline), activity_timeline.instance).has_follower(self) if hasattr( instances.get( UserTimeline.instance.get_value_for_datastore( activity_timeline), activity_timeline.instance), 'has_follower') else None, } for activity_timeline in timeline] from operator import itemgetter timeline_sorted = sorted(timeline, key=itemgetter('modified'), reverse=True) chronology = [[query_chrono.cursor(), query_activity.cursor()], timeline_sorted] return chronology def get_notifications_timeline(self, query_id=None): from models_acc import UserTimelineBase, UserTimeline, UserTimelineSuggest def prefetch_timeline(entities): # from http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine """ Carga todos los timelines apuntados por _Notifications de una sola vez """ from models_acc import UserTimelineSuggest, UserTimeline from geovote.models import Comment, Vote from geolist.models import List, ListSuggestion from geoalert.models import Event, Suggestion ref_keys = [x['timeline'] for x in entities] timelines = model_plus.get(set(ref_keys)) timelines = filter(None, timelines) # precargar las referencias timelines = model_plus.prefetch(timelines, UserTimeline.instance, UserTimeline.user) from helpers_acc import _load_ref_instances return timelines, _load_ref_instances(timelines) from models_utils import _Notification if query_id is None: query = datastore.Query(kind='_Notification', filters={'owner =': self.key()}) if query_id is not None: query = datastore.Query( kind='_Notification', filters={'owner =': self.key()}, cursor=datastore.datastore_query.Cursor.from_websafe_string( query_id)) #query.Ancestor(self.key()) query.Order(('_created', datastore.Query.DESCENDING)) timelines = query.Get(TIMELINE_PAGE_SIZE) if not any(timelines): return [] timelines, instances = prefetch_timeline(timelines) from operator import attrgetter timelines = sorted(timelines, key=attrgetter('modified'), reverse=True) import logging for t in timelines: a = instances.get(UserTimeline.instance.get_value_for_datastore(t), None) if a is None: logging.info('INSTANCE: %s' % t.instance.__class__) return [ query.GetCursor().to_websafe_string(), [{ 'id': timeline.id, 'created': timeline.created, 'modified': timeline.modified, 'msg': timeline.msg, 'username': timeline.user.username, 'msg_id': timeline.msg_id, 'instance': instances.get( UserTimeline.instance.get_value_for_datastore(timeline), timeline.instance), 'list': instances.get( UserTimelineSuggest.list_id.get_value_for_datastore( timeline), timeline.list_id) if isinstance( timeline, UserTimelineSuggest) else None, 'status': timeline.status if hasattr(timeline, 'status') else None, 'is_private': False, } for timeline in timelines] ] def following(self, async=False): ''' Devuelve la lista con todos los indices que el usuario tiene, ordenados por fecha de creacion descendente ''' from models_acc import UserFollowingIndex if async: q = UserFollowingIndex.all().ancestor(self.key()).order('-created') return q.run() return UserFollowingIndex.all().ancestor(self.key()).order('-created')