Exemplo n.º 1
0
def get_posts(user_id, page=1, per_page=None, perm=0):
    """Returns a users posts as a pagination object."""
    if per_page is None:
        per_page = app.config.get('FEED_ITEMS_PER_PAGE')

    # Get the user object we need the email for Gravatar.
    user = m.db.users.find_one({'_id': user_id},
                               {'avatar': True})

    lookup_dict = {
        'user_id': user_id,
        'reply_to': {'$exists': False}
    }

    lookup_dict['permission'] = {'$lte': perm}

    total = m.db.posts.find(lookup_dict).count()
    cursor = m.db.posts.find(lookup_dict).sort(
        'created', -1).skip((page - 1) * per_page).limit(per_page)

    posts = []
    for post in cursor:
        # This is not a nice solution but is needed for Gravatar
        if user is not None:  # pragma: no branch
            post['user_avatar'] = user.get('avatar')

        posts.append(post)

    return Pagination(posts, total, page, per_page)
Exemplo n.º 2
0
    def test_pagination(self):
        # Create a simple list of numbers to check pagination
        l = [i for i in xrange(1000)]

        p = Pagination(l[:50], len(l), 1, 50)

        # Check basic functionality
        self.assertEqual(p.total, 1000)
        # Read the number of items we have
        self.assertEqual(len(p.items), 50)
        self.assertEqual(p.items, l[:50])
        # The current page we are on
        self.assertEqual(p.page, 1)
        # Per page is how many items to show on each page
        self.assertEqual(p.per_page, 50)
        # Pages is the total number of pages in the entire list
        self.assertEqual(p.pages, 1000 / p.per_page)

        # Check the pages resolve correct
        self.assertIsNone(p.prev_page)
        self.assertIsNotNone(p.next_page)

        # We are on page 1 ensure prev_page is also 1
        self.assertIsNone(p.prev_page)
        # Ensure the next page is page 2
        self.assertEqual(p.next_page, 2)

        # Set page to the last page
        p.page = p.pages
        self.assertEqual(p.prev_page, p.page - 1)
        self.assertIsNone(p.next_page)

        # Set per_page to 0 and ensure pages is calculated ar 0
        p.per_page = 0
        self.assertEqual(p.pages, 0)

        # Try creating a pagination object with a page lower than 1
        p = Pagination(l[:50], len(l), -1, 50)
        self.assertEqual(p.page, 1)

        # Try creating a pagination object with a page larger than
        p = Pagination(l[:50], len(l), 4294967296, 50)
        self.assertEqual(p.page, 4294967295)
        self.assertIsNone(p.next_page)
        self.assertIsNotNone(p.prev_page)
Exemplo n.º 3
0
def get_alerts(user_id, page=1, per_page=None):
    """Return a list of alert objects as a pagination.

    """
    if per_page is None:
        per_page = app.config.get('ALERT_ITEMS_PER_PAGE')

    # Get the last time the users checked the alerts
    # Try and cast the value to an int so we can boolean compare them
    try:
        alerts_last_checked = m.db.users.find_one({
            '_id': user_id
        }).get('alerts_last_checked')
    except (AttributeError, TypeError, ValueError):
        alerts_last_checked = 0

    # Get total number of elements in the sorted set
    total = r.zcard(k.USER_ALERTS.format(user_id))
    aids = r.zrevrange(k.USER_ALERTS.format(user_id), (page - 1) * per_page,
                       (page * per_page) - 1)

    # Create AlertManager to load the alerts
    am = AlertManager()

    alerts = []

    for aid in aids:
        # Load the alert in to the alert manager
        alert = am.get(aid)
        if alert:
            # Check to see if the alert is newer than the time we last checked.
            # This allows us to highlight in the template
            # This will assign a new property to the object: `new`
            if int(alert.timestamp) > alerts_last_checked:
                alert.new = True

            # Add the entire alert from the manager on the list
            alerts.append(alert)
        else:
            # Self cleaning zset
            r.zrem(k.USER_ALERTS.format(user_id), aid)
            total = r.zcard(k.USER_ALERTS.format(user_id))
            # May as well delete the alert if there is one
            r.delete(k.ALERT.format(aid))

    # Update the last time the user checked there alerts
    # This will allow us to alert a user too new alerts with the /i-has-alerts
    # url
    m.db.users.update({'_id': user_id},
                      {'$set': {
                          'alerts_last_checked': timestamp()
                      }})

    return Pagination(alerts, total, page, per_page)
Exemplo n.º 4
0
    def test_pagination(self):
        # Create a simple list of numbers to check pagination
        l = [i for i in xrange(1000)]

        p = Pagination(l[:50], len(l), 1, 50)

        # Check basic functionality
        self.assertEqual(p.total, 1000)
        # Read the number of items we have
        self.assertEqual(len(p.items), 50)
        self.assertEqual(p.items, l[:50])
        # The current page we are on
        self.assertEqual(p.page, 1)
        # Per page is how many items to show on each page
        self.assertEqual(p.per_page, 50)
        # Pages is the total number of pages in the entire list
        self.assertEqual(p.pages, 1000 / p.per_page)

        # Check the pages resolve correct
        self.assertIsNone(p.prev_page)
        self.assertIsNotNone(p.next_page)

        # We are on page 1 ensure prev_page is also 1
        self.assertIsNone(p.prev_page)
        # Ensure the next page is page 2
        self.assertEqual(p.next_page, 2)

        # Set page to the last page
        p.page = p.pages
        self.assertEqual(p.prev_page, p.page - 1)
        self.assertIsNone(p.next_page)

        # Set per_page to 0 and ensure pages is calculated ar 0
        p.per_page = 0
        self.assertEqual(p.pages, 0)

        # Try creating a pagination object with a page lower than 1
        p = Pagination(l[:50], len(l), -1, 50)
        self.assertEqual(p.page, 1)

        # Try creating a pagination object with a page larger than
        p = Pagination(l[:50], len(l), 4294967296, 50)
        self.assertEqual(p.page, 4294967295)
        self.assertIsNone(p.next_page)
        self.assertIsNotNone(p.prev_page)
Exemplo n.º 5
0
def get_feed(user_id, page=1, per_page=None):
    """Returns all the posts in a users feed as a pagination object.

    .. note: The feed is stored inside Redis still as this requires fan-out to
             update all the users who are following you.
    """
    if per_page is None:
        per_page = app.config.get('FEED_ITEMS_PER_PAGE')

    # Get the total number of item in the feed and the subset for the current
    # page.
    total = r.zcard(k.USER_FEED.format(user_id))
    pids = r.zrevrange(k.USER_FEED.format(user_id), (page - 1) * per_page,
                       (page * per_page) - 1)

    # Get all the posts in one call to MongoDB
    posts = []
    cursor = m.db.posts.find({
        '_id': {
            '$in': pids
        }
    }).sort('created', pymongo.DESCENDING)

    for post in cursor:
        posts.append(post)

    # Get a list of unique `user_id`s from all the post.
    user_ids = list(set([post.get('user_id') for post in posts]))
    cursor = m.db.users.find({'_id': {'$in': user_ids}}, {'avatar': True})
    # Create a lookup dict `{username: email}`
    user_avatars = \
        dict((user.get('_id'), user.get('avatar')) for user in cursor)

    # Add the e-mails to the posts
    processed_posts = []
    for post in posts:
        post['user_avatar'] = user_avatars.get(post.get('user_id'))
        processed_posts.append(post)

    # Clean up the list in Redis if the
    if len(processed_posts) < len(pids):
        diff_pids = list(
            set(pids) - set([post.get('_id') for post in processed_posts]))
        r.zrem(k.USER_FEED.format(user_id), *diff_pids)

    return Pagination(processed_posts, total, page, per_page)
Exemplo n.º 6
0
def get_following(uid, page=1, per_page=None):
    """Returns a list of users uid is following as a pagination object."""
    if per_page is None:
        per_page = app.config.get('FEED_ITEMS_PER_PAGE')

    total = r.zcard(k.USER_FOLLOWING.format(uid))
    fids = r.zrevrange(k.USER_FOLLOWING.format(uid), (page - 1) * per_page,
                       (page * per_page) - 1)
    users = []
    for fid in fids:
        user = get_user(fid)
        if user:
            users.append(user)
        else:
            # Self cleaning sorted sets
            r.zrem(k.USER_FOLLOWING.format(uid), fid)
            total = r.zcard(k.USER_FOLLOWING.format(id))

    return Pagination(users, total, page, per_page)
Exemplo n.º 7
0
def get_hashtagged_posts(hashtag, page=1, per_page=None):
    """Returns all posts with `hashtag` in date order."""
    if per_page is None:
        per_page = app.config.get('FEED_ITEMS_PER_PAGE')

    total = m.db.posts.find({
        'hashtags.hashtag': hashtag,
        'reply_to': {'$exists': False}}).count()
    cursor = m.db.posts.find({
        'hashtags.hashtag': hashtag,
        'reply_to': {'$exists': False}
    }).sort('created', -1).skip((page - 1) * per_page).limit(per_page)

    posts = []
    for post in cursor:
        user = m.db.users.find_one(
            {'_id': post.get('user_id')},
            {'avatar': True})

        if post is not None:  # pragma: no branch
            post['user_avatar'] = user.get('avatar')
            posts.append(post)

    return Pagination(posts, total, page, per_page)
Exemplo n.º 8
0
def get_replies(post_id, page=1, per_page=None, sort_order=-1):
    """Returns all a posts replies as a pagination object."""
    if per_page is None:
        per_page = app.config.get('REPLIES_ITEMS_PER_PAGE')

    total = m.db.posts.find_one({'_id': post_id}).get('comment_count')
    cursor = m.db.posts.find(
        {'reply_to': post_id}
    ).sort(
        [('created', sort_order)]
    ).skip((page - 1) * per_page).limit(per_page)

    replies = []
    for reply in cursor:
        # We have to get the users email for each post for the gravatar
        user = m.db.users.find_one(
            {'_id': reply.get('user_id')},
            {'avatar': True})

        if user is not None:  # pragma: no branch
            reply['user_avatar'] = user.get('avatar')
            replies.append(reply)

    return Pagination(replies, total, page, per_page)
Exemplo n.º 9
0
def search(query, page=1, per_page=None):
    """Search for users / hashtagged posts (not replies)."""
    if per_page is None:
        per_page = app.config.get('FEED_ITEMS_PER_PAGE')

    # TODO: Refactor the max size of search items away
    max_items = app.config.get('MAX_SEARCH_ITEMS', 500)

    # Clean up query string
    query = query.lower().strip()

    search_hashtags = True
    search_users = True

    if query.startswith('@'):
        search_hashtags = False
    elif query.startswith('#'):
        search_users = False

    query = SEARCH_RE.sub('', query)

    if len(query) > 0:
        # Get the total number of documents returned
        results = []
        total = 0

        users = []
        if search_users:
            # We will concatenate the glob pattern to the query
            cursor = m.db.users.find({
                'username': {
                    '$regex': '^{}'.format(query)
                },
                'active': True
            }).sort('username', pymongo.ASCENDING).limit(max_items)

            # You can count the length of the cursor
            total += cursor.count()

            for user in cursor:
                users.append(user)

        posts = []
        if search_hashtags:
            cursor = m.db.posts.find({
                'hashtags.hashtag': {
                    '$regex': '^{}'.format(query)
                },
                'reply_to': {
                    '$exists': False
                }
            }).sort('hashtags.hashtag', pymongo.ASCENDING).limit(max_items)

            total += cursor.count()

            preprocessed_posts = []
            user_ids = []

            for hashtag in cursor:
                user_ids.append(hashtag.get('user_id'))
                preprocessed_posts.append(hashtag)

            cursor = m.db.users.find({'_id': {
                '$in': user_ids
            }}, {'avatar': True})
            # Create a lookup dict `{username: email}`
            user_avatars = \
                dict((user.get('_id'), user.get('avatar')) for user in cursor)

            # Add the e-mails to the posts
            for post in preprocessed_posts:
                post['user_avatar'] = user_avatars.get(post.get('user_id'))
                posts.append(post)

        results = users + posts

        def sort_results(k):
            """Allow sorting of the search results by closest matchng
            then by date the item was created."""
            if k.get('hashtags'):
                for hashtag in k.get('hashtags'):  # pragma: no branch
                    if hashtag.get('hashtag', '').startswith(query):
                        return (hashtag.get('hashtag'),
                                timestamp() - k.get('created', 0))
            else:
                return (k.get('username'), timestamp() - k.get('created', 0))

        results = sorted(results, key=sort_results)

        # Limit the mount of items in the response
        results = results[(page - 1) * per_page:page * per_page]

    else:
        # If there was not query to search for 0 off everything
        results = []
        total = 0

    # Return our pagination object
    return Pagination(results, total, page, per_page)