Пример #1
0
    def test_uploads(self):
        """Simply tests the backend functions in `lib.uploads`.

        Also tests `posts.get_upload` since this is only a simple wrapper
        around the backend function.

        """
        test_upload_dir = 'tests/upload_test_files/'
        test_upload_files = [
            join(test_upload_dir, f) for f in listdir(test_upload_dir)
            if isfile(join(test_upload_dir, f))
        ]

        # Create a GridFS object to test image deletion
        grid = gridfs.GridFS(m.db, collection='uploads')

        # Test each file in the upload directory
        for f in test_upload_files:
            # Don't read non image files in the directory
            _, ext = splitext(f)
            if ext not in ('.gif', '.jpg', '.jpeg', '.png'):
                continue

            image = io.BytesIO(
                open(f).read()
            )
            filename, animated = process_upload(image)

            # Get the upload these are designed for being served directly by
            # Flask. This is a Flask/Werkzeug response object
            image = get_upload(filename)
            self.assertTrue(grid.exists({'filename': filename}))
            self.assertEqual(image.headers['Content-Type'], 'image/png')

            if animated:
                image = get_upload(animated)
                self.assertTrue(grid.exists({'filename': animated}))
                self.assertEqual(image.headers['Content-Type'], 'image/gif')

            # Test deletion
            # Ensure file is present (it will be)
            self.assertTrue(grid.exists({'filename': filename}))
            # Delete the file and ensure it is not there through GridFS
            delete_upload(filename)
            # Ensure the file has gone
            self.assertFalse(grid.exists({'filename': filename}))

        # Ensure that if we load a non-image file a None value is returned
        image = io.BytesIO()
        self.assertEqual(process_upload(image), (None, None))
Пример #2
0
    def test_uploads(self):
        """Simply tests the backend functions in `lib.uploads`.

        Also tests `posts.get_upload` since this is only a simple wrapper
        around the backend function.

        """
        test_upload_dir = 'tests/upload_test_files/'
        test_upload_files = [
            join(test_upload_dir, f) for f in listdir(test_upload_dir)
            if isfile(join(test_upload_dir, f))
        ]

        # Create a GridFS object to test image deletion
        grid = gridfs.GridFS(m.db, collection='uploads')

        # Test each file in the upload directory
        for f in test_upload_files:
            image = io.BytesIO(open(f).read())
            filename = process_upload(image)

            # Get the upload these are designed for being served directly by
            # Flask. This is a Flask/Werkzeug response object
            image = get_upload(filename)
            self.assertTrue(grid.exists({'filename': filename}))
            self.assertEqual(image.headers['Content-Type'], 'image/png')

            # Test deletion
            # Ensure file is present (it will be)
            self.assertTrue(grid.exists({'filename': filename}))
            # Delete the file and ensure it is not there through GridFS
            delete_upload(filename)
            # Ensure the file has gone
            self.assertFalse(grid.exists({'filename': filename}))

        # Ensure that if we load a non-image file a None value is returned
        image = io.BytesIO()
        self.assertIsNone(process_upload(image))
Пример #3
0
def update_profile_settings(user_id,
                            about="",
                            hide_feed_images=False,
                            feed_size=25,
                            replies_size=25,
                            alerts_size=50,
                            reply_sort_order=-1,
                            homepage='',
                            location='',
                            upload=None,
                            permission=0):
    """Update all options on a users profile settings in MongoDB."""
    # Ensure the homepage URL is as valid as it can be
    if homepage != '':
        homepage = fix_url(homepage)

    avatar = None
    if upload:
        filename = process_upload(upload, image_size=(96, 96), thumbnail=False)
        if filename is not None:  # pragma: no cover
            avatar = filename

    update_dict = {
        'about': about,
        'hide_feed_images': hide_feed_images,
        'feed_pagination_size': int(feed_size),
        'replies_pagination_size': int(replies_size),
        'alerts_pagination_size': int(alerts_size),
        'reply_sort_order': reply_sort_order,
        'homepage': homepage,
        'location': location,
        'default_permission': int(permission)
    }

    if avatar is not None:
        update_dict['avatar'] = avatar

        user = get_user(user_id)

        if user.get('avatar'):
            # Clean up any old avatars
            # There is no update in GridFS
            delete_upload(user.get('avatar'))

    # Update the users profile
    m.db.users.update({'_id': user_id}, {'$set': update_dict})

    # Return the user object. We can update the current_user from this
    return get_user(user_id)
Пример #4
0
def update_profile_settings(user_id, about="", hide_feed_images=False,
                            feed_size=25, replies_size=25, alerts_size=50,
                            reply_sort_order=-1, homepage='', location='',
                            upload=None, permission=0):
    """Update all options on a users profile settings in MongoDB."""
    # Ensure the homepage URL is as valid as it can be
    if homepage != '':
        homepage = fix_url(homepage)

    avatar = None
    if upload:
        filename, _ = process_upload(upload, image_size=(96, 96),
                                     thumbnail=False)
        if filename is not None:  # pragma: no cover
            avatar = filename

    update_dict = {
        'about': about,
        'hide_feed_images': hide_feed_images,
        'feed_pagination_size': int(feed_size),
        'replies_pagination_size': int(replies_size),
        'alerts_pagination_size': int(alerts_size),
        'reply_sort_order': reply_sort_order,
        'homepage': homepage,
        'location': location,
        'default_permission': int(permission)
    }

    if avatar is not None:
        update_dict['avatar'] = avatar

        user = get_user(user_id)

        if user.get('avatar'):
            # Clean up any old avatars
            # There is no update in GridFS
            delete_upload(user.get('avatar'))

    # Update the users profile
    m.db.users.update({'_id': user_id}, {'$set': update_dict})

    # Return the user object. We can update the current_user from this
    return get_user(user_id)
Пример #5
0
def update_profile_settings(user_id, about="", hide_feed_images=False,
                            feed_size=25, replies_size=25, alerts_size=50,
                            homepage='', location='', upload=None):
    """Update all options on a users profile settings in MongoDB."""
    # Ensure the homepage URL is as valid as it can be
    if homepage != '':
        homepage = fix_url(homepage)

    avatar = None
    if upload:
        filename = process_upload(user_id, upload, collection='avatars',
                                  image_size=(96, 96))
        if filename is not None:  # pragma: no cover
            avatar = filename

    update_dict = {
        'about': about,
        'hide_feed_images': hide_feed_images,
        'feed_pagination_size': int(feed_size),
        'replies_pagination_size': int(replies_size),
        'alerts_pagination_size': int(alerts_size),
        'homepage': homepage,
        'location': location,
    }

    if avatar is not None:
        # Add the avatar to the dict
        update_dict['avatar'] = avatar

        # Clean up any old avatars
        # There is no update in GridFS
        grid = gridfs.GridFS(m.db, collection='avatars')
        # Get all old ones
        cursor = grid.find(
            {'filename': avatar}).sort('uploadDate', -1).skip(1)
        for f in cursor:
            grid.delete(f._id)

    # Update the users profile
    m.db.users.update({'_id': user_id}, {'$set': update_dict})

    # Return the user object. We can update the current_user from this
    return get_user(user_id)
Пример #6
0
def create_post(user_id, username, body, reply_to=None, upload=None,
                permission=k.PERM_PUBLIC):
    """Creates a new post

    This handled both posts and what used to be called comments. If the
    reply_to field is not None then the post will be treat as a comment.
    You will need to make sure the reply_to post exists.

    :param user_id: The user id of the user posting the post
    :type user_id: str
    :param username: The user name of the user posting (saves a lookup)
    :type username: str
    :param body: The content of the post
    :type body: str
    :param reply_to: The post id of the post this is a reply to if any
    :type reply_to: str
    :param upload:
    :returns: The post id of the new post
    :param permission: Who can see/interact with the post you are posting
    :type permission: int
    :rtype: str or None

    """
    # Get a new UUID for the post_id ("_id" in MongoDB)
    post_id = get_uuid()
    # Get the timestamp, we will use this to populate users feeds
    post_time = timestamp()

    post = {
        '_id': post_id,             # Newly created post id
        'user_id': user_id,         # User id of the poster
        'username': username,       # Username of the poster
        'body': body,               # Body of the post
        'created': post_time,       # Unix timestamp for this moment in time
        'score': 0,                 # Atomic score counter
    }

    if reply_to is not None:
        # If the is a reply it must have this property
        post['reply_to'] = reply_to
    else:
        # Replies don't need a comment count
        post['comment_count'] = 0
        # Set the permission a user needs to view
        post['permission'] = permission

    # TODO: Make the upload process better at dealing with issues
    if upload:
        # If there is an upload along with this post it needs to go for
        # processing.
        # process_upload() can throw an Exception of UploadError. We will let
        # it fall through as a 500 is okay I think.
        # TODO: Turn this in to a Queue task at some point
        filename = process_upload(upload)

        if filename is not None:
            # If the upload process was okay attach the filename to the doc
            post['upload'] = filename
        else:
            # Stop the image upload process here if something went wrong.
            return None

    # Process everything thats needed in a post
    links, mentions, hashtags = parse_post(body)

    # Only add the fields if we need too.
    if links:
        post['links'] = links

    if mentions:
        post['mentions'] = mentions

    if hashtags:
        post['hashtags'] = hashtags

    # Add the post to the database
    # If the post isn't stored, result will be None
    result = m.db.posts.insert(post)

    # Only carry out the rest of the actions if the insert was successful
    if result:
        if reply_to is None:
            # Add post to authors feed
            r.zadd(k.USER_FEED.format(user_id), post_time, post_id)
            # Ensure the feed does not grow to large
            r.zremrangebyrank(k.USER_FEED.format(user_id), 0, -1000)

            # Subscribe the poster to there post
            subscribe(user_id, post_id, SubscriptionReasons.POSTER)

            # Alert everyone tagged in the post
            alert_tagees(mentions, user_id, post_id)

            # Append to all followers feeds or approved followers based
            # on the posts permission
            if permission < k.PERM_APPROVED:
                populate_followers_feeds(user_id, post_id, post_time)
            else:
                populate_approved_followers_feeds(user_id, post_id, post_time)

        else:
            # To reduce database look ups on the read path we will increment
            # the reply_to's comment count.
            m.db.posts.update({'_id': reply_to},
                              {'$inc': {'comment_count': 1}})

            # Alert all subscribers to the post that a new comment has been
            # added. We do this before subscribing anyone new
            alert = CommentingAlert(user_id, reply_to)

            subscribers = []
            # Iterate through subscribers and let them know about the comment
            for subscriber_id in get_subscribers(reply_to):
                # Ensure we don't get alerted for our own comments
                if subscriber_id != user_id:
                    subscribers.append(subscriber_id)

            # Push the comment alert out to all subscribers
            AlertManager().alert(alert, subscribers)

            # Subscribe the user to the post, will not change anything if they
            # are already subscribed
            subscribe(user_id, reply_to, SubscriptionReasons.COMMENTER)

            # Alert everyone tagged in the post
            alert_tagees(mentions, user_id, reply_to)

        return post_id

    # If there was a problem putting the post in to Mongo we will return None
    return None  # pragma: no cover