Example #1
0
    def test_create_post(self):
        """Tests creating and getting a post

        """
        # Create a user to test creating post
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Create post
        post1 = create_post(user1, 'user1', 'Test post')
        # Check the post actually exists
        self.assertIsNotNone(post1)

        # Check that all the hash members are what we expect
        post = get_post(post1)
        self.assertIsNotNone(post)
        self.assertEqual(post.get('_id'), post1)
        self.assertEqual(post.get('user_id'), user1)
        self.assertEqual(post.get('body'), 'Test post')
        self.assertEqual(post.get('score'), 0)
        self.assertEqual(post.get('comment_count'), 0)
        # Check the memebers we don't know the answer to
        self.assertIsNotNone(post.get('created'))
        self.assertNotIn('upload', post)

        # Ensure this post is the users feed (populate_feed)
        self.assertIn(post1, r.zrange(K.USER_FEED.format(user1), 0, -1))

        # Testing getting post with invalid arguments
        # Test getting a post that does not exist
        self.assertIsNone(get_post(K.NIL_VALUE))

        # Create a post with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        post2 = create_post(user1, 'user1', 'Test post #2', upload=image)

        self.assertIsNotNone(post2)

        post = get_post(post2)
        self.assertIn('upload', post)
        self.assertIsNotNone(post.get('upload'))

        image = io.BytesIO(open('tests/upload_test_files/otter.gif').read())
        post3 = create_post(user1, 'user1', 'Test post #2', upload=image)

        self.assertIsNotNone(post3)

        post = get_post(post3)
        self.assertIn('upload', post)
        self.assertIn('upload_animated', post)
        self.assertIsNotNone(post.get('upload'))
        self.assertIsNotNone(post.get('upload_animated'))

        # Create a post with a broken image, ensure it's handled correctly
        image = io.BytesIO()
        post4 = create_post(user1, 'user1', 'Test post #3', upload=image)
        self.assertIsNone(post4)
        post4 = get_post(post4)
        self.assertIsNone(post4)
Example #2
0
    def test_create_reply(self):
        """Test that a reply can be made on a post

        """
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Create a second test user to test commenting on someone else post
        user2 = create_account('user2', '*****@*****.**', 'Password')
        # Create post
        post1 = create_post(user1, 'user1', 'Test post')
        # Create comment
        reply1 = create_post(user1, 'user1', 'Test comment', post1)
        # Check the comment was created
        self.assertIsNotNone(get_post(reply1))
        # Create a comment by the second user
        reply2 = create_post(user2, 'user1', 'Test comment', post1)
        # Check the comment was created
        self.assertIsNotNone(get_post(reply2))

        # Check the comment hash has the data we expect, we will do this with
        # comment1
        comment = get_post(reply1)
        self.assertIsNotNone(comment)
        self.assertEqual(comment.get('_id'), reply1)
        self.assertEqual(comment.get('user_id'), user1)
        self.assertEqual(comment.get('reply_to'), post1)
        self.assertEqual(comment.get('body'), 'Test comment')
        self.assertEqual(comment.get('score'), 0)
        self.assertIsNotNone(comment.get('created'))
        self.assertNotIn('upload', comment)

        # Create a post with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        reply1 = create_post(user1,
                             'user1',
                             'Test post #2',
                             reply_to=post1,
                             upload=image)

        self.assertIsNotNone(reply1)

        comment = get_post(reply1)
        self.assertIn('upload', comment)
        self.assertIsNotNone(comment.get('upload'))

        # Create a post with a broken image, ensure it's handled correctly
        image = io.BytesIO()
        reply2 = create_post(user1,
                             'user1',
                             'Test post #3',
                             reply_to=post1,
                             upload=image)
        self.assertIsNone(reply2)
        comment = get_post(reply2)
        self.assertIsNone(comment)
Example #3
0
    def test_create_reply(self):
        """Test that a reply can be made on a post

        """
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Create a second test user to test commenting on someone else post
        user2 = create_account('user2', '*****@*****.**', 'Password')
        # Create post
        post1 = create_post(user1, 'user1', 'Test post')
        # Create comment
        reply1 = create_post(user1, 'user1', 'Test comment', post1)
        # Check the comment was created
        self.assertIsNotNone(get_post(reply1))
        # Create a comment by the second user
        reply2 = create_post(user2, 'user1', 'Test comment', post1)
        # Check the comment was created
        self.assertIsNotNone(get_post(reply2))

        # Check the comment hash has the data we expect, we will do this with
        # comment1
        comment = get_post(reply1)
        self.assertIsNotNone(comment)
        self.assertEqual(comment.get('_id'), reply1)
        self.assertEqual(comment.get('user_id'), user1)
        self.assertEqual(comment.get('reply_to'), post1)
        self.assertEqual(comment.get('body'), 'Test comment')
        self.assertEqual(comment.get('score'), 0)
        self.assertIsNotNone(comment.get('created'))
        self.assertNotIn('upload', comment)

        # Create a post with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        reply1 = create_post(user1, 'user1', 'Test post #2', reply_to=post1,
                             upload=image)

        self.assertIsNotNone(reply1)

        comment = get_post(reply1)
        self.assertIn('upload', comment)
        self.assertIsNotNone(comment.get('upload'))

        # Create a post with a broken image, ensure it's handled correctly
        image = io.BytesIO()
        reply2 = create_post(user1, 'user1', 'Test post #3', reply_to=post1,
                             upload=image)
        self.assertIsNone(reply2)
        comment = get_post(reply2)
        self.assertIsNone(comment)
Example #4
0
    def test_get_upload(self):
        """Tests the simple wrapper around ``lib.uploads.get_upload``

        """
        user1 = create_account('user1', '*****@*****.**', 'Password')
        activate(user1)

        # Create the post with an upload to get
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        post1 = create_post(user1, 'user1', 'Test post', upload=image)
        self.assertIsNotNone(post1)

        post = get_post(post1)

        # Try and get the post and ensure we are redirected because we are not
        # logged in
        resp = self.client.get(url_for('posts.get_upload',
                                       filename=post.get('upload')))
        self.assertEqual(resp.status_code, 302)

        # Log in as user1 and get the upload
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)

        resp = self.client.get(url_for('posts.get_upload',
                                       filename=post.get('upload')))
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.headers['Content-Type'], 'image/png')
Example #5
0
def get_stats():
    """Provides post level statistics.

    """
    total_posts = m.db.posts.count()
    total_uploads = m.db.posts.find(
        {'upload': {'$exists': True}}).count()

    last_post = m.db.posts.find().sort(
        [('created', pymongo.DESCENDING)]).limit(1)
    try:
        last_post_time = timeify_filter(last_post[0].get('created'))
    except IndexError:
        last_post_time = None

    # Get the 10 highest flagged posts if there is any
    flagged_posts_cur = m.db.posts.find(
        {'flags': {'$gt': 0}}).sort('flags', pymongo.DESCENDING).limit(10)

    flagged_posts = []
    for flagged_post in flagged_posts_cur:
        s = '{0} - <a href="{1}">{2}</a>: <a href="{3}">{4}</a>' + \
            ' [<a href="{5}">Unflag</a>]'

        if flagged_post.get('reply_to') is not None:
            reply_to = get_post(flagged_post.get('reply_to'))
            username = reply_to.get('username')
            post_id = reply_to.get('_id')
        else:
            username = flagged_post.get('username')
            post_id = flagged_post.get('_id')

        link = s.format(
            flagged_post.get('flags'),
            url_for('users.profile',
                    username=flagged_post.get('username')),
            flagged_post.get('username'),
            url_for('posts.view_post',
                    username=username,
                    post_id=post_id),
            flagged_post.get('_id'),
            url_for('posts.unflag_post', post_id=flagged_post.get('_id'))
        )

        # Highligh comments
        if flagged_post.get('reply_to') is not None:
            link = link + ' (comment)'

        flagged_posts.append(link)

    if len(flagged_posts) == 0:
        flagged_posts.append('Empty')

    return [
        ('Total posts', total_posts),
        ('Total uploads', total_uploads),
        ('Last post', last_post_time),
        ('Flagged posts', flagged_posts)
    ]
Example #6
0
    def test_permission_setting(self):
        """Test that a post can have correct permissions set"""
        user1 = create_account('user1', '*****@*****.**', 'Password')

        # Create post with each permission
        post1 = create_post(user1, 'user1', 'Test post', permission=0)
        post2 = create_post(user1, 'user1', 'Test post', permission=1)
        post3 = create_post(user1, 'user1', 'Test post', permission=2)

        post = get_post(post1)
        self.assertEqual(post.get('permission'), 0)

        post = get_post(post2)
        self.assertEqual(post.get('permission'), 1)

        post = get_post(post3)
        self.assertEqual(post.get('permission'), 2)
Example #7
0
    def test_create_post(self):
        """Tests creating and getting a post

        """
        # Create a user to test creating post
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Create post
        post1 = create_post(user1, 'user1', 'Test post')
        # Check the post actually exists
        self.assertIsNotNone(post1)

        # Check that all the hash members are what we expect
        post = get_post(post1)
        self.assertIsNotNone(post)
        self.assertEqual(post.get('_id'), post1)
        self.assertEqual(post.get('user_id'), user1)
        self.assertEqual(post.get('body'), 'Test post')
        self.assertEqual(post.get('score'), 0)
        self.assertEqual(post.get('comment_count'), 0)
        # Check the memebers we don't know the answer to
        self.assertIsNotNone(post.get('created'))
        self.assertNotIn('upload', post)

        # Ensure this post is the users feed (populate_feed)
        self.assertIn(post1, r.zrange(K.USER_FEED.format(user1), 0, -1))

        # Testing getting post with invalid arguments
        # Test getting a post that does not exist
        self.assertIsNone(get_post(K.NIL_VALUE))

        # Create a post with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        post2 = create_post(user1, 'user1', 'Test post #2', upload=image)

        self.assertIsNotNone(post2)

        post = get_post(post2)
        self.assertIn('upload', post)
        self.assertIsNotNone(post.get('upload'))

        # Create a post with a broken image, ensure it's handled correctly
        image = io.BytesIO()
        post3 = create_post(user1, 'user1', 'Test post #3', upload=image)
        self.assertIsNone(post3)
        post3 = get_post(post3)
        self.assertIsNone(post3)
Example #8
0
    def test_permission_setting(self):
        """Test that a post can have correct permissions set"""
        user1 = create_account('user1', '*****@*****.**', 'Password')

        # Create post with each permission
        post1 = create_post(user1, 'user1', 'Test post', permission=0)
        post2 = create_post(user1, 'user1', 'Test post', permission=1)
        post3 = create_post(user1, 'user1', 'Test post', permission=2)

        post = get_post(post1)
        self.assertEqual(post.get('permission'), 0)

        post = get_post(post2)
        self.assertEqual(post.get('permission'), 1)

        post = get_post(post3)
        self.assertEqual(post.get('permission'), 2)
Example #9
0
def get_stats():
    """Provides post level statistics.

    """
    total_posts = m.db.posts.count()
    total_uploads = m.db.posts.find({"upload": {"$exists": True}}).count()

    last_post = m.db.posts.find().sort([("created", pymongo.DESCENDING)]).limit(1)
    try:
        last_post_time = timeify_filter(last_post[0].get("created"))
    except IndexError:
        last_post_time = None

    # Get the 10 highest flagged posts if there is any
    flagged_posts_cur = m.db.posts.find({"flags": {"$gt": 0}}).sort("flags", pymongo.DESCENDING).limit(10)

    flagged_posts = []
    for flagged_post in flagged_posts_cur:
        s = '{0} - <a href="{1}">{2}</a>: <a href="{3}">{4}</a>' + ' [<a href="{5}">Unflag</a>]'

        if flagged_post.get("reply_to") is not None:
            reply_to = get_post(flagged_post.get("reply_to"))
            username = reply_to.get("username")
            post_id = reply_to.get("_id")
        else:
            username = flagged_post.get("username")
            post_id = flagged_post.get("_id")

        link = s.format(
            flagged_post.get("flags"),
            url_for("users.profile", username=flagged_post.get("username")),
            flagged_post.get("username"),
            url_for("posts.view_post", username=username, post_id=post_id),
            flagged_post.get("_id"),
            url_for("posts.unflag_post", post_id=flagged_post.get("_id")),
        )

        # Highligh comments
        if flagged_post.get("reply_to") is not None:
            link = link + " (comment)"

        flagged_posts.append(link)

    if len(flagged_posts) == 0:
        flagged_posts.append("Empty")

    return [
        ("Total posts", total_posts),
        ("Total uploads", total_uploads),
        ("Last post", last_post_time),
        ("Flagged posts", flagged_posts),
    ]
Example #10
0
def view_post(username, pid):
    """
    Displays a post along with its comments paginated. I am not sure if this
    should be here or in the 'posts' app.
    """
    if not check_post(get_uid(username), pid):
        return abort(404)

    # Pagination
    page = handle_page(request)

    # Get post
    post = get_post(pid)
    # Get comments
    pagination = get_comments(pid, page)
    post_form = PostForm()
    return render_template('view_post.html', post=post,
                           pagination=pagination, post_form=post_form)
Example #11
0
File: backend.py Project: hnk/pjuu
def get_feed(user_id, page=1):
    """Returns 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.
    """
    per_page = app.config.get('FEED_ITEMS_PER_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)
    posts = []
    for pid in pids:
        # Get the post
        post = get_post(pid)
        if post:
            posts.append(post)
        else:
            # Self cleaning lists
            r.zrem(k.USER_FEED.format(user_id), pid)
            total = r.zcard(k.USER_FEED.format(user_id))

    return Pagination(posts, total, page, per_page)
Example #12
0
    def test_delete(self):
        """
        Tests delete_post() does what it should.
        This will in turn test delete_comments() as this will be triggered when
        a post is deleted.
        """
        # Create three test users
        user1 = create_account('user1', '*****@*****.**', 'Password')
        user2 = create_account('user2', '*****@*****.**', 'Password')

        # Create a post
        post1 = create_post(user1, 'user1', 'Test post')
        # Create multiple comments
        reply1 = create_post(user1, 'user1', 'Test comment 1', post1)
        reply2 = create_post(user2, 'user2', 'Test comment 2', post1)
        reply3 = create_post(user1, 'user1', 'Test comment 3', post1)
        reply4 = create_post(user2, 'user2', 'Test comment 4', post1)

        # Check the comment count on post1 is correct
        self.assertEqual(get_post(post1).get('comment_count'), 4)

        # Test deleting one comment
        # This function does not actually test to see if the user has the
        # the rights to delete the post. This should be tested in the frontend
        # Check a comment can be deleted
        self.assertIsNone(delete_post(reply4))

        # Check that getting the comment returns None
        self.assertIsNone(get_post(reply4))

        # Ensure the comment count on post1 is correct
        self.assertEqual(get_post(post1).get('comment_count'), 3)

        # Delete the post. This should delete all the comments, we will check
        self.assertIsNone(delete_post(post1))
        # Check that the post does not exist
        self.assertIsNone(get_post(post1))
        # Check that non of the comments exist
        self.assertIsNone(get_post(reply1))
        self.assertIsNone(get_post(reply2))
        self.assertIsNone(get_post(reply3))

        # Test deleting posts with uploads
        # Ensuring that the images are gone.
        # The actual deleting is tested in 'test_uploads.py'
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        post1 = create_post(user1, 'user1', 'Test post #2', upload=image)
        self.assertIsNotNone(post1)
        post1_filename = get_post(post1).get('upload')

        # Reset the file position in the image
        image.seek(0)
        reply1 = create_post(user1, 'user1', 'Test comment 1', post1,
                             upload=image)
        self.assertIsNotNone(reply1)
        reply1_filename = get_post(reply1).get('upload')

        image.seek(0)
        reply2 = create_post(user2, 'user2', 'Test comment 2', post1,
                             upload=image)
        self.assertIsNotNone(reply2)
        reply2_filename = get_post(reply2).get('upload')

        # Create GridFS file checker
        grid = gridfs.GridFS(m.db, 'uploads')

        # Check that each file exists
        self.assertTrue(grid.exists({'filename': post1_filename}))
        self.assertTrue(grid.exists({'filename': reply1_filename}))
        self.assertTrue(grid.exists({'filename': reply2_filename}))

        self.assertIsNone(delete_post(post1))

        # Check that all the files no longer exist
        self.assertFalse(grid.exists({'filename': post1_filename}))
        self.assertFalse(grid.exists({'filename': reply1_filename}))
        self.assertFalse(grid.exists({'filename': reply2_filename}))
Example #13
0
    def test_votes(self):
        """
        Test that the voting mechanism will adjust the relevant score counters
        on users, posts and comments, etc...
        """
        # Create three test users
        user1 = create_account('user1', '*****@*****.**', 'Password')
        user2 = create_account('user2', '*****@*****.**', 'Password')
        user3 = create_account('user3', '*****@*****.**', 'Password')

        # Create a post by user 1
        post1 = create_post(user1, 'user1', 'Test post')

        # Get user 3 to downvote, this will test that the user can not go
        # negative yet the post can
        self.assertIsNone(vote_post(user3, post1, amount=-1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), -1)
        # Ensure user score has NOT been adjusted
        self.assertEqual(get_user(user1).get('score'), 0)

        # Get user 2 to upvote
        self.assertIsNone(vote_post(user2, post1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure user 1 can not vote on there own post
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, post1))
        # Ensure the scores have not been adjusted
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 1)

        # Check to see if a user can vote twice on a post
        self.assertRaises(AlreadyVoted, lambda: vote_post(user2, post1))
        # Ensure the scores have not been adjusted
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 1)

        # Repeat the same tests on a comment
        # Create a comment by user 1
        comment1 = create_post(user1, 'user1', 'Test comment', post1)

        # Let's cheat and set user1's score back to 0 so we can check it will
        # not be lowered in the user3 downvote
        m.db.users.update({'_id': user1},
                          {'$set': {'score': 0}})

        # Get user 3 to downvote
        self.assertIsNone(vote_post(user3, comment1, amount=-1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1)['score'], -1)
        # Ensure user score has NOT been adjusted
        self.assertEqual(get_user(user1)['score'], 0)

        # Get user 2 to upvote
        self.assertIsNone(vote_post(user2, comment1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure user 1 can not vote on there own comment
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, comment1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        # Check to see if a user can vote twice on a comment
        self.assertRaises(AlreadyVoted, lambda: vote_post(user2, comment1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)
Example #14
0
    def test_votes(self):
        """
        Test that the voting mechanism will adjust the relevant score counters
        on users, posts and comments, etc...
        """
        # Create three test users
        user1 = create_account('user1', '*****@*****.**', 'Password')
        user2 = create_account('user2', '*****@*****.**', 'Password')
        user3 = create_account('user3', '*****@*****.**', 'Password')

        # Create a post by user 1
        post1 = create_post(user1, 'user1', 'Test post')

        # Get user 3 to downvote
        self.assertEqual(vote_post(user3, post1, amount=-1), -1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), -1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), -1)

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user3, post1, amount=-1), 0)
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Get user 2 to upvote
        self.assertEqual(vote_post(user2, post1), 1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), 1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure user 1 can not vote on there own post
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, post1))
        # Ensure the scores have not been adjusted
        self.assertEqual(get_post(post1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure the user has voted
        self.assertTrue(has_voted(user2, post1))

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user2, post1), 0)
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Ensure the user has voted
        self.assertFalse(has_voted(user2, post1))

        # Check that the score reflects an opposite vote within TIMEOUT
        self.assertEqual(vote_post(user2, post1, 1), 1)
        self.assertEqual(get_post(post1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, post1))

        self.assertEqual(vote_post(user2, post1, -1), -1)
        self.assertEqual(get_post(post1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        self.assertTrue(has_voted(user2, post1))

        # Check that a user can not reverse there vote after the TIMEOUT
        self.assertRaises(AlreadyVoted,
                          lambda: vote_post(user2, post1, -1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        self.assertRaises(AlreadyVoted,
                          lambda: vote_post(user2, post1, 1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        # Repeat the same tests on a comment
        # Create a comment by user 1
        comment1 = create_post(user1, 'user1', 'Test comment', post1)

        # Let's cheat and set user1's score back to 0
        m.db.users.update({'_id': user1},
                          {'$set': {'score': 0}})

        # Get user 3 to downvote
        self.assertEqual(vote_post(user3, comment1, amount=-1), -1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        # Reverse user3's vote just so it's not confusing
        self.assertEqual(vote_post(user3, comment1, amount=-1), 0)
        self.assertEqual(get_post(comment1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Ensure user 1 can not vote on there own comment
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, comment1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 0)

        # Get user 2 to upvote
        self.assertEqual(vote_post(user2, comment1), 1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, comment1))

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user2, comment1), 0)
        self.assertEqual(get_post(comment1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        self.assertFalse(has_voted(user2, comment1))

        # Check that the score reflects an opposite vote within TIMEOUT
        self.assertEqual(vote_post(user2, comment1, -1), -1)
        self.assertEqual(get_post(comment1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        self.assertTrue(has_voted(user2, comment1))

        self.assertEqual(vote_post(user2, comment1, 1), 1)
        self.assertEqual(get_post(comment1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, comment1))

        # Check that a user can not reverse there vote after the TIMEOUT
        self.assertRaises(AlreadyVoted,
                          lambda: vote_post(user2, comment1, -1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        self.assertRaises(AlreadyVoted,
                          lambda: vote_post(user2, comment1, 1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))
Example #15
0
    def test_post(self):
        """
        Test that we can post too Pjuu.
        """
        # Lets ensure we can't GET the /post endpoint
        # You should not be able to GET this resouce but you will not see this
        # until you are signed in. This should simply redirect us to login
        resp = self.client.get(url_for('posts.post'))
        self.assertEqual(resp.status_code, 302)

        # Lets ensure we can't POST to /post when logged out
        # As above we should simply be redirected
        resp = self.client.post(url_for('posts.post'), data={
            'body': 'Test post'
        })
        self.assertEqual(resp.status_code, 302)

        # Let's create a user an login
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Activate the account
        self.assertTrue(activate(user1))
        # Log the user in
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)

        # We are now logged in :) Let's ensure we can't GET the /post endpoint
        resp = self.client.get(url_for('posts.post'))
        self.assertEqual(resp.status_code, 405)

        # Lets post a test post
        # Because we are not passing a next query param we will be redirected
        # to /test (users profile) after this post
        resp = self.client.post(url_for('posts.post'), data={
            'body': 'Test post'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure our new post appears in the output
        self.assertIn('Test post', resp.data)
        # We should be on the posts view as we did not pass a next qs
        self.assertIn('<!-- author post -->', resp.data)

        # Let's post again but this time lets redirect ourselves back to feed.
        # We will ensure both posts exist in the feed
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': 'Second test post'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure both posts are their
        self.assertIn('Test post', resp.data)
        self.assertIn('Second test post', resp.data)

        # The post endpoint also handles populating followers feeds. We will
        # create a couple of users (in the backend, we will not test the
        # frontend here).
        user2 = create_account('user2', '*****@*****.**', 'Password')
        activate(user2)
        follow_user(user2, user1)

        user3 = create_account('user3', '*****@*****.**', 'Password')
        activate(user3)
        follow_user(user3, user1)

        # Create a post as user 1, we will then log out and ensure these posts
        # appear in the other users lists
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': 'Hello followers'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure all posts are their
        self.assertIn('Test post', resp.data)
        self.assertIn('Second test post', resp.data)
        self.assertIn('Hello followers', resp.data)
        # Let's ensure the post form is their
        self.assertIn('<!-- author post -->', resp.data)

        # We are using the test client so lets log out properly
        self.client.get(url_for('auth.signout'))

        # Log in as test2 and ensure the post is in their feed
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        self.assertIn('Hello followers', resp.data)
        # Log out
        self.client.get(url_for('auth.signout'))

        # Log in as test3 and ensure the post in their feed
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        self.assertIn('Hello followers', resp.data)
        # Log out
        self.client.get(url_for('auth.signout'))

        # Sign back in as user1 so that we can keep testing
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)

        # Back to testing. Let's ensure that users can post unicode text
        # I copied this Chinese text from a header file on my Mac. I do not
        # know what it means, I just need the characters
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': '光铸钥匙'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure all posts are their
        self.assertIn('Test post', resp.data)
        self.assertIn('Second test post', resp.data)
        self.assertIn('Hello followers', resp.data)
        self.assertIn('光铸钥匙', resp.data)

        # Check that a muted user can not create a post
        # Mute out user
        mute(user1)
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': 'Muting test'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure the warning is there
        self.assertIn('You have been silenced!', resp.data)
        self.assertNotIn('Muting test', resp.data)
        # Un-mute the user and try and post the same thing
        self.assertTrue(mute(user1, False))
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': 'Muting test'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Let's ensure the warning is there
        self.assertNotIn('You have been silenced!', resp.data)
        self.assertIn('Muting test', resp.data)

        # Try and post to many characters
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': ('P' * (MAX_POST_LENGTH + 1))
        }, follow_redirects=True)
        self.assertIn('Posts can not be larger than '
                      '{0} characters'.format(MAX_POST_LENGTH), resp.data)

        # Test that we can post 500 unicode characters
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': ('光' * (MAX_POST_LENGTH))
        }, follow_redirects=True)
        self.assertNotIn('Posts can not be larger than '
                         '{0} characters'.format(MAX_POST_LENGTH), resp.data)

        # Test that we can not post more than MAX_POST_LENGTH unicode
        # characters
        resp = self.client.post(url_for('posts.post',
                                        next=url_for('users.feed')),
                                data={
            'body': ('光' * (MAX_POST_LENGTH + 1))
        }, follow_redirects=True)
        self.assertIn('Posts can not be larger than '
                      '{0} characters'.format(MAX_POST_LENGTH), resp.data)

        # Ensure that posting an image with no text still doesn't allow it
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        resp = self.client.post(
            url_for('posts.post'),
            data={
                'body': '',
                'upload': (image, 'otter.jpg')
            },
            follow_redirects=True
        )
        self.assertEqual(resp.status_code, 200)
        self.assertIn('A message is required.', resp.data)

        # Test posting with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        resp = self.client.post(
            url_for('posts.post'),
            data={
                'body': 'Test upload',
                'upload': (image, 'otter.jpg')
            },
            follow_redirects=True
        )

        self.assertEqual(resp.status_code, 200)

        # Goto the users feed an ensure the post is there
        resp = self.client.get(url_for('users.feed'))
        self.assertEqual(resp.status_code, 200)

        # So that we can check the data is in the templates, upload a post
        # in the backend and ensure it appears where it should
        image = io.BytesIO(open('tests/upload_test_files/otter.png').read())
        post1 = create_post(user1, 'user1', 'Test post', upload=image)
        self.assertIsNotNone(post1)
        post = get_post(post1)
        resp = self.client.get(url_for('users.feed'))
        self.assertIn('<!-- upload:post:%s -->' % post1, resp.data)
        self.assertIn('<img src="%s"/>' % url_for('posts.get_upload',
                                                  filename=post.get('upload')),
                      resp.data)

        # Although the below belongs in `test_view_post` we are just going to
        # check it here for simplicity
        resp = self.client.get(url_for('posts.view_post', username='******',
                                       post_id=post1))
        self.assertIn('<!-- upload:post:%s -->' % post1, resp.data)
        self.assertIn('<img src="%s"/>' % url_for('posts.get_upload',
                                                  filename=post.get('upload')),
                      resp.data)
Example #16
0
    def test_delete(self):
        """
        Tests delete_post() does what it should.
        This will in turn test delete_comments() as this will be triggered when
        a post is deleted.
        """
        # Create three test users
        user1 = create_account('user1', '*****@*****.**', 'Password')
        user2 = create_account('user2', '*****@*****.**', 'Password')

        # Create a post
        post1 = create_post(user1, 'user1', 'Test post')
        # Create multiple comments
        reply1 = create_post(user1, 'user1', 'Test comment 1', post1)
        reply2 = create_post(user2, 'user2', 'Test comment 2', post1)
        reply3 = create_post(user1, 'user1', 'Test comment 3', post1)
        reply4 = create_post(user2, 'user2', 'Test comment 4', post1)

        # Check the comment count on post1 is correct
        self.assertEqual(get_post(post1).get('comment_count'), 4)

        # Test deleting one comment
        # This function does not actually test to see if the user has the
        # the rights to delete the post. This should be tested in the frontend
        # Check a comment can be deleted
        self.assertIsNone(delete_post(reply4))

        # Check that getting the comment returns None
        self.assertIsNone(get_post(reply4))

        # Ensure the comment count on post1 is correct
        self.assertEqual(get_post(post1).get('comment_count'), 3)

        # Delete the post. This should delete all the comments, we will check
        self.assertIsNone(delete_post(post1))
        # Check that the post does not exist
        self.assertIsNone(get_post(post1))
        # Check that non of the comments exist
        self.assertIsNone(get_post(reply1))
        self.assertIsNone(get_post(reply2))
        self.assertIsNone(get_post(reply3))

        # Test deleting posts with uploads
        # Ensuring that the images are gone.
        # The actual deleting is tested in 'test_uploads.py'
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        post1 = create_post(user1, 'user1', 'Test post #2', upload=image)
        self.assertIsNotNone(post1)
        post1_filename = get_post(post1).get('upload')

        # Reset the file position in the image
        image.seek(0)
        reply1 = create_post(user1,
                             'user1',
                             'Test comment 1',
                             post1,
                             upload=image)
        self.assertIsNotNone(reply1)
        reply1_filename = get_post(reply1).get('upload')

        image.seek(0)
        reply2 = create_post(user2,
                             'user2',
                             'Test comment 2',
                             post1,
                             upload=image)
        self.assertIsNotNone(reply2)
        reply2_filename = get_post(reply2).get('upload')

        # Create GridFS file checker
        grid = gridfs.GridFS(m.db, 'uploads')

        # Check that each file exists
        self.assertTrue(grid.exists({'filename': post1_filename}))
        self.assertTrue(grid.exists({'filename': reply1_filename}))
        self.assertTrue(grid.exists({'filename': reply2_filename}))

        self.assertIsNone(delete_post(post1))

        # Check that all the files no longer exist
        self.assertFalse(grid.exists({'filename': post1_filename}))
        self.assertFalse(grid.exists({'filename': reply1_filename}))
        self.assertFalse(grid.exists({'filename': reply2_filename}))
Example #17
0
    def test_votes(self):
        """
        Test that the voting mechanism will adjust the relevant score counters
        on users, posts and comments, etc...
        """
        # Create three test users
        user1 = create_account('user1', '*****@*****.**', 'Password')
        user2 = create_account('user2', '*****@*****.**', 'Password')
        user3 = create_account('user3', '*****@*****.**', 'Password')

        # Create a post by user 1
        post1 = create_post(user1, 'user1', 'Test post')

        # Get user 3 to downvote
        self.assertEqual(vote_post(user3, post1, amount=-1), -1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), -1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), -1)

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user3, post1, amount=-1), 0)
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Get user 2 to upvote
        self.assertEqual(vote_post(user2, post1), 1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(post1).get('score'), 1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure user 1 can not vote on there own post
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, post1))
        # Ensure the scores have not been adjusted
        self.assertEqual(get_post(post1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        # Ensure the user has voted
        self.assertTrue(has_voted(user2, post1))

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user2, post1), 0)
        self.assertEqual(get_post(post1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Ensure the user has voted
        self.assertFalse(has_voted(user2, post1))

        # Check that the score reflects an opposite vote within TIMEOUT
        self.assertEqual(vote_post(user2, post1, 1), 1)
        self.assertEqual(get_post(post1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, post1))

        self.assertEqual(vote_post(user2, post1, -1), -1)
        self.assertEqual(get_post(post1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        self.assertTrue(has_voted(user2, post1))

        # Check that a user can not reverse there vote after the TIMEOUT
        self.assertRaises(
            AlreadyVoted, lambda: vote_post(user2, post1, -1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        self.assertRaises(
            AlreadyVoted, lambda: vote_post(user2, post1, 1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        # Repeat the same tests on a comment
        # Create a comment by user 1
        comment1 = create_post(user1, 'user1', 'Test comment', post1)

        # Let's cheat and set user1's score back to 0
        m.db.users.update({'_id': user1}, {'$set': {'score': 0}})

        # Get user 3 to downvote
        self.assertEqual(vote_post(user3, comment1, amount=-1), -1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        # Reverse user3's vote just so it's not confusing
        self.assertEqual(vote_post(user3, comment1, amount=-1), 0)
        self.assertEqual(get_post(comment1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        # Ensure user 1 can not vote on there own comment
        self.assertRaises(CantVoteOnOwn, lambda: vote_post(user1, comment1))
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 0)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 0)

        # Get user 2 to upvote
        self.assertEqual(vote_post(user2, comment1), 1)
        # Ensure post score has been adjusted
        self.assertEqual(get_post(comment1).get('score'), 1)
        # Ensure user score has been adjusted
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, comment1))

        # Check that a user can reverse their vote within TIMEOUT
        self.assertEqual(vote_post(user2, comment1), 0)
        self.assertEqual(get_post(comment1).get('score'), 0)
        self.assertEqual(get_user(user1).get('score'), 0)

        self.assertFalse(has_voted(user2, comment1))

        # Check that the score reflects an opposite vote within TIMEOUT
        self.assertEqual(vote_post(user2, comment1, -1), -1)
        self.assertEqual(get_post(comment1).get('score'), -1)
        self.assertEqual(get_user(user1).get('score'), -1)

        self.assertTrue(has_voted(user2, comment1))

        self.assertEqual(vote_post(user2, comment1, 1), 1)
        self.assertEqual(get_post(comment1).get('score'), 1)
        self.assertEqual(get_user(user1).get('score'), 1)

        self.assertTrue(has_voted(user2, comment1))

        # Check that a user can not reverse there vote after the TIMEOUT
        self.assertRaises(
            AlreadyVoted, lambda: vote_post(user2, comment1, -1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))

        self.assertRaises(
            AlreadyVoted, lambda: vote_post(user2, comment1, 1,
                                            timestamp() + K.VOTE_TIMEOUT + 1))
Example #18
0
    def test_replies(self):
        """
        Test commenting on a post. This is a lot simpler than making a post
        """
        # We can not test getting to a comment as we need a post and a user
        # for this too happen

        # Let's create a user and login
        user1 = create_account('user1', '*****@*****.**', 'Password')
        # Activate the account
        activate(user1)
        # Log the user in
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)

        # Create a post to comment on we will do this in the backend to get
        # the pid
        post1 = create_post(user1, 'user1', 'Test post')

        # Lets attempt to GET to the comment view. Should fail we can only POST
        # like we can to /post
        resp = self.client.get(url_for('posts.post', username='******',
                                       post_id=post1))
        # Method not allowed
        self.assertEqual(resp.status_code, 405)

        # Lets post a comment and follow the redirects this should take us to
        # the comment page
        resp = self.client.post(url_for('posts.post', username='******',
                                        post_id=post1),
                                data={'body': 'Test comment'},
                                follow_redirects=True)
        # Lets check that we can see the comment
        self.assertEqual(resp.status_code, 200)
        self.assertIn('Test comment', resp.data)
        # Lets also make sure the form is visible on the page
        self.assertIn('<!-- author reply -->', resp.data)

        # Lets signout
        resp = self.client.get(url_for('auth.signout'))
        self.assertEqual(resp.status_code, 302)

        # Lets create another test user and ensure that they can see the
        # comment
        user2 = create_account('user2', '*****@*****.**', 'password')
        # Activate the account
        activate(user2)
        # Log the user in
        resp = self.client.post(url_for('auth.signin'), data={
            'username': '******',
            'password': '******'
        }, follow_redirects=True)
        self.assertEqual(resp.status_code, 200)

        # Lets just check that we can see the comment if we go to the view_post
        # view
        resp = self.client.get(url_for('posts.view_post', username='******',
                                       post_id=post1))
        self.assertEqual(resp.status_code, 200)
        self.assertIn('Test comment', resp.data)

        # Lets comment ourselves
        resp = self.client.post(url_for('posts.post', username='******',
                                        post_id=post1),
                                data={'body': 'Test comment 2'},
                                follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Check that the 2 comments exist
        self.assertIn('Test comment', resp.data)
        self.assertIn('Test comment 2', resp.data)

        # Lets check we can not comment if we are muted
        mute(user2)
        resp = self.client.post(url_for('posts.post', username='******',
                                        post_id=post1),
                                data={'body': 'Muting test'},
                                follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Check that the comment was never posted
        self.assertIn('You have been silenced!', resp.data)
        self.assertNotIn('Muting test', resp.data)

        # Reverse the muting and test again
        mute(user2, False)
        resp = self.client.post(url_for('posts.post', username='******',
                                        post_id=post1),
                                data={'body': 'Muting test'},
                                follow_redirects=True)
        self.assertEqual(resp.status_code, 200)
        # Check that the comment was never posted
        self.assertNotIn('You have been silenced!', resp.data)
        self.assertIn('Muting test', resp.data)

        # Try and post to many characters
        resp = self.client.post(url_for('posts.post', username='******',
                                        post_id=post1), data={
            'body': ('P' * (MAX_POST_LENGTH + 1))
        }, follow_redirects=True)
        self.assertIn('Posts can not be larger than '
                      '{0} characters'.format(MAX_POST_LENGTH), resp.data)

        # Test replies with an image
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        resp = self.client.post(
            url_for('posts.post', username='******', post_id=post1),
            data={
                'body': 'Test upload',
                'upload': (image, 'otter.jpg')
            },
            follow_redirects=True
        )

        self.assertEqual(resp.status_code, 200)

        # So that we can check the data is in the templates, upload a post
        # in the backend and ensure it appears where it should
        image = io.BytesIO(open('tests/upload_test_files/otter.png').read())
        reply_img = create_post(user1, 'user1', 'Test post', reply_to=post1,
                                upload=image)
        self.assertIsNotNone(reply_img)
        reply = get_post(reply_img)
        resp = self.client.get(url_for('posts.view_post', username='******',
                                       post_id=post1))
        self.assertIn('<!-- upload:reply:%s -->' % reply_img, resp.data)
        self.assertIn('<img src="%s"/>' % url_for(
            'posts.get_upload', filename=reply.get('upload')), resp.data)

        # Ensure that posting an image with no text still doesn't allow it
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        resp = self.client.post(
            url_for('posts.post', username='******', post_id=post1),
            data={
                'body': '',
                'upload': (image, 'otter.jpg')
            },
            follow_redirects=True
        )
        self.assertEqual(resp.status_code, 200)
        self.assertIn('A message is required.', resp.data)

        # Ensure that an invalid filename is stopped by the forms
        image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read())
        resp = self.client.post(
            url_for('posts.post', username='******', post_id=post1),
            data={
                'body': 'Test',
                'upload': (image, 'otter.cheese')
            },
            follow_redirects=True
        )
        self.assertEqual(resp.status_code, 200)
        self.assertIn('Only "gif", "jpg", "jpeg" and "png" files are '
                      'supported', resp.data)