示例#1
0
    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
示例#2
0
 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
示例#3
0
 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
示例#4
0
    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
示例#5
0
    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
示例#6
0
    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]]
示例#7
0
 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
示例#8
0
 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
示例#9
0
 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)
示例#10
0
 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)
示例#11
0
 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
示例#12
0
    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
示例#13
0
    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
            ],
        ]
示例#14
0
 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]
     ]
示例#15
0
 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))]]
示例#16
0
    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]
        ]
示例#17
0
 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]
示例#18
0
    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
示例#19
0
    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
示例#20
0
 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
示例#21
0
 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
示例#22
0
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')