def delete_post(username, post_id, reply_id=None): """Deletes posts. """ # The default redirect is different for a post/reply deletion # Reply deletion keeps you on the page and post deletion takes you to feed if reply_id is not None: redirect_url = handle_next( request, url_for('posts.view_post', username=username, post_id=post_id)) else: redirect_url = handle_next(request, url_for('users.feed')) user_id = get_uid(username) if not check_post(user_id, post_id, reply_id): return abort(404) if reply_id is not None: _post = get_post(reply_id) if _post['user_id'] != current_user['_id'] and \ user_id != current_user['_id']: return abort(403) else: if user_id != current_user['_id']: return abort(403) if reply_id is not None: be_delete_post(reply_id) flash('Post has been deleted', 'success') else: be_delete_post(post_id) flash('Post has been deleted along with all replies', 'success') return redirect(redirect_url)
def delete_post(username, post_id, reply_id=None): """Deletes posts. """ # The default redirect is different for a post/reply deletion # Reply deletion keeps you on the page and post deletion takes you to feed if reply_id is not None: redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) else: redirect_url = handle_next(request, url_for('users.feed')) user_id = get_uid(username) if not check_post(user_id, post_id, reply_id): return abort(404) if reply_id is not None: _post = get_post(reply_id) if _post['user_id'] != current_user['_id'] and \ user_id != current_user['_id']: return abort(403) else: if user_id != current_user['_id']: return abort(403) if reply_id is not None: be_delete_post(reply_id) flash('Post has been deleted', 'success') else: be_delete_post(post_id) flash('Post has been deleted along with all replies', 'success') return redirect(redirect_url)
def flag(username, post_id): """Flags a post so that moderators are aware of it. .. note: This is a requirement to enter the Apple app store. """ # Ensure the default redirect is to the correct location. reply_id = get_post(post_id).get('reply_to') if reply_id is None: redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) else: reply = get_post(reply_id) redirect_url = handle_next(request, url_for('posts.view_post', username=reply.get('username'), post_id=reply_id)) user_id = get_uid(username) if not check_post(user_id, post_id): return abort(404) try: flag_post(current_user['_id'], post_id) except CantFlagOwn: flash('You can not flag on your own posts', 'error') except AlreadyFlagged: flash('You have already flagged this post', 'error') else: flash('You flagged the ' + ('comment' if reply_id else 'post'), 'success') return redirect(redirect_url)
def remove_from_feed(post_id): """Removes ``post_id`` from current users feed.""" redirect_url = handle_next(request, url_for('users.feed')) if be_rem_from_feed(post_id, current_user.get('_id')): # pragma: no branch flash('Message has been removed from feed', 'success') return redirect(handle_next(request, redirect_url))
def post(username=None, post_id=None): """Enabled current_user to create a new post on Pjuu :) This view accepts GET and POST yet only acts on a POST. This is so that the Werkzeug router does not treat this like a profile lookup. """ # Rather than just 404 if someone tries to GET this URL (which is default), # we will throw a 405. if request.method == 'GET': return abort(405) # Set the default redirect URLs depending on type of post it is if post_id is None: redirect_url = handle_next(request, url_for('users.profile', username=current_user['username'])) else: redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) # Stop muted users from creating posts if current_user.get('muted', False): flash('You have been silenced!', 'warning') return redirect(redirect_url) form = PostForm() if form.validate(): # If there is an uploaded File pass it on else pass nothing if form.upload.data: # Pass the BytesIO stream to the backend. upload = form.upload.data.stream else: upload = None # Create the post if create_post(current_user['_id'], current_user['username'], form.body.data, post_id, upload): # Inform the user we have created the post flash('Your post has been added', 'success') else: flash('There was an error creating your post', 'error') # pragma: no cover else: # Will print out all errors that happen in a post form. # This is better than "There is an error in your post" for key, value in form.errors.iteritems(): for error in value: flash(error, 'error') return redirect(redirect_url)
def signin(): """ Logs a user in. Will authenticate username/password, check account activation and if the user is banned or not before setting user_id in session. """ form = SignInForm(request.form) if request.method == 'POST': # Handles the passing of the next argument to the login view redirect_url = handle_next(request, url_for('feed')) if form.validate(): # Calls authenticate from backend.py uid = authenticate(form.username.data, form.password.data) if uid: # Ensure the user is active if not is_active(uid): flash('Please activate your account<br />' 'Check your e-mail', 'information') # Ensure the user is not banned elif is_banned(uid): flash('You\'re a very naughty boy!', 'error') # All OK log the user in else: # We will also make the session permanent if the user # has requested too session.permanent = form.keep_signed_in.data login(uid) return redirect(redirect_url) else: flash('Invalid user name or password', 'error') else: flash('Invalid user name or password', 'error') return render_template('signin.html', form=form)
def downvote(username, post_id, reply_id=None): """Downvotes a post. """ redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) user_id = get_uid(username) if not check_post(user_id, post_id, reply_id): return abort(404) try: if reply_id is None: vote_post(current_user['_id'], post_id, amount=-1) else: vote_post(current_user['_id'], reply_id, amount=-1) except AlreadyVoted: flash('You have already voted on this post', 'error') except CantVoteOnOwn: flash('You can not vote on your own posts', 'error') else: flash('You downvoted the ' + ("comment" if reply_id else "post"), 'success') return redirect(redirect_url)
def comment(username, pid): """ current_user creates a comment of post 'pid' with the author 'username' """ # Rather than just 404 if someone tries to GET this URL which is default # if we don't specify it we will throw a 405. if request.method == 'GET': return abort(405) redirect_url = handle_next(request, url_for('view_post', username=username, pid=pid)) # Stop muted users from commenting if is_mute(current_user['uid']): flash('You have been silenced!', 'warning') return redirect(redirect_url) form = PostForm(request.form) if form.validate(): cid = create_comment(current_user['uid'], pid, form.body.data) flash('Your comment has been added', 'success') else: # This flash can handle only 1 form error # There is an odd issue where are error is thrown with no errors # Can't recreate the issue if len(form.body.errors) > 0: flash(form.body.errors[0], 'error') else: flash('Oh no! There are errors in your comment.', 'error') # pragma: no cover return redirect(redirect_url)
def signin(): """ """ form = SignInForm(request.form) if request.method == 'POST': # Handles the passing of the next argument to the login view redirect_url = handle_next(request, url_for('users.feed')) if form.validate(): # Calls authenticate from backend.py user = authenticate(form.username.data, form.password.data) if user: # Ensure the user is active if not user.get('active', False): flash('Please activate your account<br />' 'Check your e-mail', 'information') # Ensure the user is not banned elif user.get('banned', False): flash('You\'re a very naughty boy!', 'error') # All OK log the user in else: # We will also make the session permanent if the user # has requested too session.permanent = form.keep_signed_in.data be_signin(user.get('_id')) return redirect(redirect_url) else: flash('Invalid user name or password', 'error') else: flash('Invalid user name or password', 'error') return render_template('signin.html', form=form)
def downvote(username, pid=-1, cid=None): """ Downvotes a post or comment. If this is a comment it _WILL_ update the comments authros score. The 'username' may seem a little confusing but the comment is on the 'pid' which was created by 'username'. """ redirect_url = handle_next(request, url_for('view_post', username=username, pid=pid)) uid = get_uid(username) if not check_post(uid, pid, cid): return abort(404) try: if cid: result = vote_comment(current_user['uid'], cid, amount=-1) else: result = vote_post(current_user['uid'], pid, amount=-1) except AlreadyVoted: flash('You have already voted on this post', 'error') except CantVoteOnOwn: flash('You can not vote on your own posts', 'error') else: flash('You downvoted the post', 'success') return redirect(redirect_url)
def post(redirect_url=None): """ current_user creates a new post on Pjuu :) This view accepts GET and POST yet only acts on a POST. This is so that the Werkzeug router does not treat this like a profile lookup """ # Rather than just 404 if someone tries to GET this URL which is default # if we don't specify it we will throw a 405. if request.method == 'GET': return abort(405) redirect_url = handle_next(request, url_for('profile', username=current_user['username'])) # Stop muted users from creating posts if is_mute(current_user['uid']): flash('You have been silenced!', 'warning') return redirect(redirect_url) form = PostForm(request.form) if form.validate(): pid = create_post(current_user['uid'], form.body.data) flash('Your post has been added', 'success') else: # This flash can handle only 1 form error # There is an odd issue where are error is thrown with no errors # Can't recreate the issue if len(form.body.errors) > 0: flash(form.body.errors[0], 'error') else: flash('Oh no! There are errors in your post.', 'error') # pragma: no cover return redirect(redirect_url)
def signin(): """ """ form = SignInForm(request.form) if request.method == 'POST': # Handles the passing of the next argument to the login view redirect_url = handle_next(request, url_for('users.feed')) if form.validate(): # Calls authenticate from backend.py user = authenticate(form.username.data, form.password.data) if user: # Ensure the user is active if not user.get('active', False): flash( 'Please activate your account<br />' 'Check your e-mail', 'information') # Ensure the user is not banned elif user.get('banned', False): flash('You\'re a very naughty boy!', 'error') # All OK log the user in else: # We will also make the session permanent if the user # has requested too session.permanent = form.keep_signed_in.data be_signin(user.get('_id')) return redirect(redirect_url) else: flash('Invalid user name or password', 'error') else: flash('Invalid user name or password', 'error') return render_template('signin.html', form=form)
def reset_tips(): """Allow a user to reset all the tips from their settings page""" redirect_url = handle_next(request, url_for('users.settings_profile')) # Actually reset the tips in the database be_reset_tips(current_user.get('_id')) flash('Tip\'s have successfully been reset', 'success') return redirect(redirect_url)
def flag(username, post_id): """Flags a post so that moderators are aware of it. .. note: This is a requirement to enter the Apple app store. """ if not check_post(get_uid(username), post_id): return abort(404) _post = get_post(post_id) # Ensure the default redirect is to the correct location. reply_id = get_post(post_id).get('reply_to') if reply_id is None: redirect_url = handle_next( request, url_for('posts.view_post', username=username, post_id=post_id)) else: reply = get_post(reply_id) redirect_url = handle_next( request, url_for('posts.view_post', username=reply.get('username'), post_id=reply_id)) # Ensue user has permission to perform the action current_user_id = current_user.get('_id') permission = get_user_permission(_post.get('user_id'), current_user_id) if permission < _post.get('permission', k.PERM_PUBLIC): flash('You do not have permission to flag this post', 'error') return redirect(redirect_url) try: flag_post(current_user['_id'], post_id) except CantFlagOwn: flash('You can not flag on your own posts', 'error') except AlreadyFlagged: flash('You have already flagged this post', 'error') else: flash('You flagged the ' + ('comment' if reply_id else 'post'), 'success') return redirect(redirect_url)
def delete_alert(alert_id): """Remove an alert id (aid) from a users alerts feed.""" user_id = current_user.get('_id') # Handle next redirect_url = handle_next(request, url_for('users.alerts')) if be_delete_alert(user_id, alert_id): flash('Alert has been hidden', 'success') return redirect(redirect_url)
def hide_tip(tip_name): """Will set a tip with `tip_name` to false for the `current_user`""" if tip_name not in k.VALID_TIP_NAMES: return abort(404) # Set the tip to False inside Mongo remove_tip(current_user.get('_id'), tip_name) redirect_url = handle_next(request, url_for('users.feed')) return redirect(redirect_url)
def delete_post(username, pid, cid=None): """ Deletes posts and comments. """ # The default redirect is different for a post/comment deletion # Comment deletion keeps you on the page and post deletion takes you # to your feed if cid is not None: redirect_url = handle_next(request, url_for('view_post', username=username, pid=pid)) else: redirect_url = handle_next(request, url_for('feed')) uid = get_uid(username) if not check_post(uid, pid, cid): return abort(404) if cid is not None: author_uid = get_comment_author(cid) # Allow not only the comment author to remove the comment but also # allow the post author to do so! if author_uid != current_user['uid'] and \ uid != current_user['uid']: return abort(403) else: # If this is a post ONLY allow the post author to delete if uid != current_user['uid']: return abort(403) if cid is not None: be_delete_comment(cid) flash('Comment has been deleted', 'success') else: be_delete_post(pid) flash('Post has been deleted along with all comments', 'success') return redirect(redirect_url)
def unsubscribe(username, post_id): """Unsubscribes a user from a post """ if not check_post(get_uid(username), post_id): return abort(404) # The default URL is to go back to the posts view redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) # Unsubscribe the user from the post, only show them a message if they # were actually unsubscribed if be_unsubscribe(current_user['_id'], post_id): flash('You have been unsubscribed from this post', 'success') return redirect(redirect_url)
def unsubscribe(username, post_id): """Unsubscribes a user from a post """ if not check_post(get_uid(username), post_id): return abort(404) # The default URL is to go back to the posts view redirect_url = handle_next( request, url_for('posts.view_post', username=username, post_id=post_id)) # Unsubscribe the user from the post, only show them a message if they # were actually unsubscribed if be_unsubscribe(current_user['_id'], post_id): flash('You have been unsubscribed from this post', 'success') return redirect(redirect_url)
def unfollow(username): """Unfollow a user""" redirect_url = handle_next(request, url_for('users.following', username=current_user.get('username'))) user_id = get_uid(username) # If we don't get a uid from the username the page doesn't exist if user_id is None: abort(404) # Unfollow user, ensure the user doesn't unfollow themself if user_id != current_user.get('_id'): if unfollow_user(current_user.get('_id'), user_id): flash('You are no longer following %s' % username, 'success') else: flash('You can\'t follow/unfollow yourself', 'information') return redirect(redirect_url)
def unfollow(username): """Unfollow a user""" redirect_url = handle_next( request, url_for('users.following', username=current_user.get('username'))) user_id = get_uid(username) # If we don't get a uid from the username the page doesn't exist if user_id is None: abort(404) # Unfollow user, ensure the user doesn't unfollow themself if user_id != current_user.get('_id'): if unfollow_user(current_user.get('_id'), user_id): flash('You are no longer following %s' % username, 'success') else: flash('You can\'t follow/unfollow yourself', 'information') return redirect(redirect_url)
def unapprove(username): """Unfollow a user""" redirect_url = handle_next( request, url_for('users.followers', username=current_user.get('username'))) user_id = get_uid(username) # If we don't get a uid from the username the page doesn't exist if user_id is None: abort(404) if user_id != current_user.get('_id'): if unapprove_user(current_user.get('_id'), user_id): flash('You have untrusted %s' % username, 'success') else: flash('You can\'t untrust a user who is not trusted', 'error') else: flash('You can\'t untrust your self', 'information') return redirect(redirect_url)
def unapprove(username): """Unfollow a user""" redirect_url = handle_next(request, url_for('users.followers', username=current_user.get('username'))) user_id = get_uid(username) # If we don't get a uid from the username the page doesn't exist if user_id is None: abort(404) if user_id != current_user.get('_id'): if unapprove_user(current_user.get('_id'), user_id): flash('You have untrusted %s' % username, 'success') else: flash('You can\'t untrust a user who is not trusted', 'error') else: flash('You can\'t untrust your self', 'information') return redirect(redirect_url)
def remove_from_feed(post_id): """Removes ``post_id`` from current users feed""" if be_remove_from_feed(post_id, current_user.get('_id')): flash('Message has been removed from feed', 'success') return redirect(handle_next(request, url_for('users.feed')))
def vote(username, post_id, reply_id=None): """Upvotes a post. .. note: If the request is an XHR one the whole function will not run. It will exit out and the first chance and return JSON. """ redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) if not check_post(get_uid(username), post_id, reply_id): if request.is_xhr: return jsonify({'message': 'Post not found'}), 404 return abort(404) _post = get_post(post_id) # Ensuer user has permission to perform the action current_user_id = current_user.get('_id') permission = get_user_permission(_post.get('user_id'), current_user_id) # Since the upvote/downvote functions have been merged we need to # identify which action is going to be performed. if request.endpoint == 'posts.upvote': action = 'upvoted' amount = 1 else: action = 'downvoted' amount = -1 if permission < _post.get('permission', k.PERM_PUBLIC): message = 'You do not have permission to vote on this post' if request.is_xhr: return jsonify({'message': message}), 403 xflash(message, 'error') return redirect(redirect_url) try: if reply_id is None: result = vote_post(current_user['_id'], post_id, amount=amount) else: result = vote_post(current_user['_id'], reply_id, amount=amount) except AlreadyVoted: message = 'You have already voted on this post' if request.is_xhr: return jsonify({'message': message}), 400 xflash(message, 'error') except CantVoteOnOwn: message = 'You can not vote on your own posts' if request.is_xhr: return jsonify({'message': message}), 400 xflash(message, 'error') else: if (amount > 0 < result) or (amount < 0 > result): message = 'You {} the '.format(action) + ("comment" if reply_id else "post") xflash(message, 'success') else: message = 'You reversed your vote on the ' + ("comment" if reply_id else "post") xflash(message, 'success') if request.is_xhr: return jsonify({'message': message}), 200 return redirect(redirect_url)
def post(username=None, post_id=None): """Enabled current_user to create a new post on Pjuu :) This view accepts GET and POST yet only acts on a POST. This is so that the Werkzeug router does not treat this like a profile lookup. """ # Rather than just 404 if someone tries to GET this URL (which is default), # we will throw a 405. if request.method == 'GET': return abort(405) # Stop un-approved users posting comments if permissions do not let them. if post_id is not None: if not check_post(get_uid(username), post_id): return abort(404) _post = get_post(post_id) permission = get_user_permission(current_user, _post.get('_id')) if permission < _post.get('permission', k.PERM_PUBLIC): return abort(403) # Set the default redirect URLs depending on type of post it is if post_id is None: redirect_url = handle_next(request, url_for('users.profile', username=current_user['username'])) else: redirect_url = handle_next(request, url_for('posts.view_post', username=username, post_id=post_id)) # Stop muted users from creating posts if current_user.get('muted', False): flash('You have been silenced!', 'warning') return redirect(redirect_url) form = PostForm() if form.validate(): # If there is an uploaded File pass it on else pass nothing if form.upload.data: # Pass the BytesIO stream to the backend. upload = form.upload.data.stream else: upload = None try: permission = int(form.permission.data) except ValueError: # pragma: no cover permission = -1 # WTForms should stop this ever, ever firing if not (k.PERM_PUBLIC <= permission <= # pragma: no cover k.PERM_APPROVED): # pragma: no cover flash('Invalid post permission set', 'error') return redirect(redirect_url) # Create the post if create_post(current_user['_id'], current_user['username'], unicode(escape(form.body.data)), post_id, upload, permission=permission): # Inform the user we have created the post flash('Your post has been added', 'success') else: flash('There was an error creating your post', 'error') # pragma: no cover else: # Will print out all errors that happen in a post form. # This is better than "There is an error in your post" for key, value in form.errors.iteritems(): for error in value: flash(error, 'error') return redirect(redirect_url)
def post(username=None, post_id=None): """Enabled current_user to create a new post on Pjuu :) This view accepts GET and POST yet only acts on a POST. This is so that the Werkzeug router does not treat this like a profile lookup. """ # Rather than just 404 if someone tries to GET this URL (which is default), # we will throw a 405. if request.method == 'GET': return abort(405) # Stop un-approved users posting comments if permissions do not let them. if post_id is not None: if not check_post(get_uid(username), post_id): return abort(404) _post = get_post(post_id) permission = get_user_permission(current_user, _post.get('_id')) if permission < _post.get('permission', k.PERM_PUBLIC): return abort(403) # Set the default redirect URLs depending on type of post it is if post_id is None: redirect_url = handle_next( request, url_for('users.profile', username=current_user['username'])) else: redirect_url = handle_next( request, url_for('posts.view_post', username=username, post_id=post_id)) # Stop muted users from creating posts if current_user.get('muted', False): flash('You have been silenced!', 'warning') return redirect(redirect_url) form = PostForm() if form.validate(): # If there is an uploaded File pass it on else pass nothing if form.upload.data: # Pass the BytesIO stream to the backend. upload = form.upload.data.stream else: upload = None try: permission = int(form.permission.data) except ValueError: # pragma: no cover permission = -1 # WTForms should stop this ever, ever firing if not (k.PERM_PUBLIC <= permission <= # pragma: no cover k.PERM_APPROVED): # pragma: no cover flash('Invalid post permission set', 'error') return redirect(redirect_url) # Create the post if create_post(current_user['_id'], current_user['username'], unicode(escape(form.body.data)), post_id, upload, permission=permission): # Inform the user we have created the post flash('Your post has been added', 'success') else: flash('There was an error creating your post', 'error') # pragma: no cover else: # Will print out all errors that happen in a post form. # This is better than "There is an error in your post" for key, value in form.errors.iteritems(): for error in value: flash(error, 'error') return redirect(redirect_url)
def vote(username, post_id, reply_id=None): """Upvotes a post. .. note: If the request is an XHR one the whole function will not run. It will exit out and the first chance and return JSON. """ redirect_url = handle_next( request, url_for('posts.view_post', username=username, post_id=post_id)) if not check_post(get_uid(username), post_id, reply_id): if request.is_xhr: return jsonify({'message': 'Post not found'}), 404 return abort(404) _post = get_post(post_id) # Ensuer user has permission to perform the action current_user_id = current_user.get('_id') permission = get_user_permission(_post.get('user_id'), current_user_id) # Since the upvote/downvote functions have been merged we need to # identify which action is going to be performed. if request.endpoint == 'posts.upvote': action = 'upvoted' amount = 1 else: action = 'downvoted' amount = -1 if permission < _post.get('permission', k.PERM_PUBLIC): message = 'You do not have permission to vote on this post' if request.is_xhr: return jsonify({'message': message}), 403 xflash(message, 'error') return redirect(redirect_url) try: if reply_id is None: result = vote_post(current_user['_id'], post_id, amount=amount) else: result = vote_post(current_user['_id'], reply_id, amount=amount) except AlreadyVoted: message = 'You have already voted on this post' if request.is_xhr: return jsonify({'message': message}), 400 xflash(message, 'error') except CantVoteOnOwn: message = 'You can not vote on your own posts' if request.is_xhr: return jsonify({'message': message}), 400 xflash(message, 'error') else: if (amount > 0 < result) or (amount < 0 > result): message = 'You {} the '.format(action) + ("comment" if reply_id else "post") xflash(message, 'success') else: message = 'You reversed your vote on the ' + ("comment" if reply_id else "post") xflash(message, 'success') if request.is_xhr: return jsonify({'message': message}), 200 return redirect(redirect_url)