mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
API: add post/save and comment/save routes (aka bookmarks)
This commit is contained in:
parent
990b7250cb
commit
2de2f9ed2d
7 changed files with 218 additions and 19 deletions
|
@ -1,7 +1,7 @@
|
|||
from app.api.alpha import bp
|
||||
from app.api.alpha.utils import get_site, \
|
||||
get_post_list, get_post, post_post_like, \
|
||||
get_reply_list, post_reply_like, \
|
||||
get_post_list, get_post, post_post_like, put_post_save, \
|
||||
get_reply_list, post_reply_like, put_reply_save, \
|
||||
get_community_list, get_community, \
|
||||
get_user
|
||||
from app.shared.auth import log_user_in
|
||||
|
@ -83,6 +83,18 @@ def post_alpha_post_like():
|
|||
return jsonify({"error": str(ex)}), 400
|
||||
|
||||
|
||||
@bp.route('/api/alpha/post/save', methods=['PUT'])
|
||||
def put_alpha_post_save():
|
||||
if not current_app.debug:
|
||||
return jsonify({'error': 'alpha api routes only available in debug mode'})
|
||||
try:
|
||||
auth = request.headers.get('Authorization')
|
||||
data = request.get_json(force=True) or {}
|
||||
return jsonify(put_post_save(auth, data))
|
||||
except Exception as ex:
|
||||
return jsonify({"error": str(ex)}), 400
|
||||
|
||||
|
||||
# Reply
|
||||
@bp.route('/api/alpha/comment/list', methods=['GET'])
|
||||
def get_alpha_comment_list():
|
||||
|
@ -108,6 +120,18 @@ def post_alpha_comment_like():
|
|||
return jsonify({"error": str(ex)}), 400
|
||||
|
||||
|
||||
@bp.route('/api/alpha/comment/save', methods=['PUT'])
|
||||
def put_alpha_comment_save():
|
||||
if not current_app.debug:
|
||||
return jsonify({'error': 'alpha api routes only available in debug mode'})
|
||||
try:
|
||||
auth = request.headers.get('Authorization')
|
||||
data = request.get_json(force=True) or {}
|
||||
return jsonify(put_reply_save(auth, data))
|
||||
except Exception as ex:
|
||||
return jsonify({"error": str(ex)}), 400
|
||||
|
||||
|
||||
# User
|
||||
@bp.route('/api/alpha/user', methods=['GET'])
|
||||
def get_alpha_user():
|
||||
|
@ -171,7 +195,6 @@ def alpha_community():
|
|||
@bp.route('/api/alpha/post/remove', methods=['POST'])
|
||||
@bp.route('/api/alpha/post/lock', methods=['POST'])
|
||||
@bp.route('/api/alpha/post/feature', methods=['POST'])
|
||||
@bp.route('/api/alpha/post/like', methods=['POST'])
|
||||
@bp.route('/api/alpha/post/save', methods=['PUT'])
|
||||
@bp.route('/api/alpha/post/report', methods=['POST'])
|
||||
@bp.route('/api/alpha/post/report/resolve', methods=['PUT'])
|
||||
|
@ -188,7 +211,6 @@ def alpha_post():
|
|||
@bp.route('/api/alpha/comment/remove', methods=['POST'])
|
||||
@bp.route('/api/alpha/comment/mark_as_read', methods=['POST'])
|
||||
@bp.route('/api/alpha/comment/distinguish', methods=['POST'])
|
||||
@bp.route('/api/alpha/comment/save', methods=['PUT'])
|
||||
@bp.route('/api/alpha/comment/report', methods=['POST'])
|
||||
@bp.route('/api/alpha/comment/report/resolve', methods=['PUT'])
|
||||
@bp.route('/api/alpha/comment/report/list', methods=['GET'])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from app.api.alpha.utils.site import get_site
|
||||
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like
|
||||
from app.api.alpha.utils.reply import get_reply_list, post_reply_like
|
||||
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like, put_post_save
|
||||
from app.api.alpha.utils.reply import get_reply_list, post_reply_like, put_reply_save
|
||||
from app.api.alpha.utils.community import get_community, get_community_list
|
||||
from app.api.alpha.utils.user import get_user
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from app import cache
|
||||
from app.api.alpha.views import post_view
|
||||
from app.api.alpha.utils.validators import required, integer_expected
|
||||
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected
|
||||
from app.models import Post, Community, CommunityMember, utcnow
|
||||
from app.shared.post import vote_for_post
|
||||
from app.shared.post import vote_for_post, bookmark_the_post, remove_the_bookmark_from_post
|
||||
from app.utils import authorise_api_user
|
||||
|
||||
from datetime import timedelta
|
||||
|
@ -128,6 +128,28 @@ def post_post_like(auth, data):
|
|||
raise
|
||||
|
||||
|
||||
def put_post_save(auth, data):
|
||||
try:
|
||||
required(['post_id', 'save'], data)
|
||||
integer_expected(['post_id'], data)
|
||||
boolean_expected(['save'], data)
|
||||
except:
|
||||
raise
|
||||
|
||||
post_id = data['post_id']
|
||||
save = data['save']
|
||||
|
||||
try:
|
||||
if save is True:
|
||||
user_id = bookmark_the_post(post_id, SRC_API, auth)
|
||||
else:
|
||||
user_id = remove_the_bookmark_from_post(post_id, SRC_API, auth)
|
||||
post_json = post_view(post=post_id, variant=4, user_id=user_id)
|
||||
return post_json
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from app import cache
|
||||
from app.utils import authorise_api_user
|
||||
from app.api.alpha.utils.validators import required, integer_expected
|
||||
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected
|
||||
from app.api.alpha.views import reply_view
|
||||
from app.models import PostReply
|
||||
from app.shared.reply import vote_for_reply
|
||||
from app.shared.reply import vote_for_reply, bookmark_the_post_reply, remove_the_bookmark_from_post_reply
|
||||
|
||||
from sqlalchemy import desc
|
||||
|
||||
|
@ -93,4 +93,26 @@ def post_reply_like(auth, data):
|
|||
raise
|
||||
|
||||
|
||||
def put_reply_save(auth, data):
|
||||
try:
|
||||
required(['comment_id', 'save'], data)
|
||||
integer_expected(['comment_id'], data)
|
||||
boolean_expected(['save'], data)
|
||||
except:
|
||||
raise
|
||||
|
||||
reply_id = data['comment_id']
|
||||
save = data['save']
|
||||
|
||||
try:
|
||||
if save is True:
|
||||
user_id = bookmark_the_post_reply(reply_id, SRC_API, auth)
|
||||
else:
|
||||
user_id = remove_the_bookmark_from_post_reply(reply_id, SRC_API, auth)
|
||||
reply_json = reply_view(reply=reply_id, variant=4, user_id=user_id)
|
||||
return reply_json
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -50,8 +50,10 @@ def post_view(post: Post | int, variant, stub=False, user_id=None, my_vote=0):
|
|||
# counts - models/post/post_aggregates.dart
|
||||
counts = {'post_id': post.id, 'comments': post.reply_count, 'score': post.score, 'upvotes': post.up_votes, 'downvotes': post.down_votes,
|
||||
'published': post.posted_at.isoformat() + 'Z', 'newest_comment_time': post.last_active.isoformat() + 'Z'}
|
||||
bookmarked = db.session.execute(text('SELECT user_id FROM "post_bookmark" WHERE post_id = :post_id and user_id = :user_id'), {'post_id': post.id, 'user_id': user_id}).scalar()
|
||||
saved = True if bookmarked else False
|
||||
v2 = {'post': post_view(post=post, variant=1, stub=stub), 'counts': counts, 'banned_from_community': False, 'subscribed': 'NotSubscribed',
|
||||
'saved': False, 'read': False, 'hidden': False, 'creator_blocked': False, 'unread_comments': post.reply_count, 'my_vote': my_vote}
|
||||
'saved': saved, 'read': False, 'hidden': False, 'creator_blocked': False, 'unread_comments': post.reply_count, 'my_vote': my_vote}
|
||||
|
||||
try:
|
||||
creator = user_view(user=post.user_id, variant=1, stub=True)
|
||||
|
@ -95,7 +97,7 @@ def post_view(post: Post | int, variant, stub=False, user_id=None, my_vote=0):
|
|||
|
||||
return v3
|
||||
|
||||
# Variant 4 - models/post/post_response.dart - /post/like api endpoint
|
||||
# Variant 4 - models/post/post_response.dart - api endpoint for /post/like and post/save
|
||||
if variant == 4:
|
||||
v4 = {'post_view': post_view(post=post, variant=2, user_id=user_id)}
|
||||
|
||||
|
@ -255,8 +257,10 @@ def reply_view(reply: PostReply | int, variant, user_id=None, my_vote=0):
|
|||
# counts - models/comment/comment_aggregates.dart
|
||||
counts = {'comment_id': reply.id, 'score': reply.score, 'upvotes': reply.up_votes, 'downvotes': reply.down_votes,
|
||||
'published': reply.posted_at.isoformat() + 'Z', 'child_count': 1 if calculate_if_has_children(reply) else 0}
|
||||
bookmarked = db.session.execute(text('SELECT user_id FROM "post_reply_bookmark" WHERE post_reply_id = :post_reply_id and user_id = :user_id'), {'post_reply_id': reply.id, 'user_id': user_id}).scalar()
|
||||
saved = True if bookmarked else False
|
||||
v2 = {'comment': reply_view(reply=reply, variant=1), 'counts': counts, 'banned_from_community': False, 'subscribed': 'NotSubscribed',
|
||||
'saved': False, 'creator_blocked': False, 'my_vote': my_vote}
|
||||
'saved': saved, 'creator_blocked': False, 'my_vote': my_vote}
|
||||
try:
|
||||
creator = user_view(user=reply.user_id, variant=1, stub=True)
|
||||
community = community_view(community=reply.community_id, variant=1, stub=True)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from app import cache
|
||||
from app import cache, db
|
||||
from app.activitypub.signature import default_context, post_request_in_background
|
||||
from app.community.util import send_to_remote_instance
|
||||
from app.models import Post, User
|
||||
from app.models import Post, PostBookmark, User
|
||||
from app.utils import gibberish, instance_banned, render_template, authorise_api_user, recently_upvoted_posts, recently_downvoted_posts
|
||||
|
||||
from flask import current_app, request
|
||||
from flask import abort, current_app, flash, redirect, request, url_for
|
||||
from flask_babel import _
|
||||
from flask_login import current_user
|
||||
|
||||
|
||||
|
@ -92,3 +93,68 @@ def vote_for_post(post_id: int, vote_direction, src, auth=None):
|
|||
template = 'post/_post_voting_buttons.html' if request.args.get('style', '') == '' else 'post/_post_voting_buttons_masonry.html'
|
||||
return render_template(template, post=post, community=post.community, recently_upvoted=recently_upvoted,
|
||||
recently_downvoted=recently_downvoted)
|
||||
|
||||
|
||||
# function can be shared between WEB and API (only API calls it for now)
|
||||
# post_bookmark in app/post/routes would just need to do 'return bookmark_the_post(post_id, SRC_WEB)'
|
||||
def bookmark_the_post(post_id: int, src, auth=None):
|
||||
if src == SRC_API and auth is not None:
|
||||
post = Post.query.get(post_id)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
try:
|
||||
user_id = authorise_api_user(auth)
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
if post.deleted:
|
||||
abort(404)
|
||||
user_id = current_user.id
|
||||
|
||||
existing_bookmark = PostBookmark.query.filter(PostBookmark.post_id == post_id, PostBookmark.user_id == user_id).first()
|
||||
if not existing_bookmark:
|
||||
db.session.add(PostBookmark(post_id=post_id, user_id=user_id))
|
||||
db.session.commit()
|
||||
if src == SRC_WEB:
|
||||
flash(_('Bookmark added.'))
|
||||
else:
|
||||
if src == SRC_WEB:
|
||||
flash(_('This post has already been bookmarked.'))
|
||||
|
||||
if src == SRC_API:
|
||||
return user_id
|
||||
else:
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
||||
# function can be shared between WEB and API (only API calls it for now)
|
||||
# post_remove_bookmark in app/post/routes would just need to do 'return remove_the_bookmark_from_post(post_id, SRC_WEB)'
|
||||
def remove_the_bookmark_from_post(post_id: int, src, auth=None):
|
||||
if src == SRC_API and auth is not None:
|
||||
post = Post.query.get(post_id)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
try:
|
||||
user_id = authorise_api_user(auth)
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
if post.deleted:
|
||||
abort(404)
|
||||
user_id = current_user.id
|
||||
|
||||
existing_bookmark = PostBookmark.query.filter(PostBookmark.post_id == post_id, PostBookmark.user_id == user_id).first()
|
||||
if existing_bookmark:
|
||||
db.session.delete(existing_bookmark)
|
||||
db.session.commit()
|
||||
if src == SRC_WEB:
|
||||
flash(_('Bookmark has been removed.'))
|
||||
|
||||
if src == SRC_API:
|
||||
return user_id
|
||||
else:
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from app import cache
|
||||
from app import cache, db
|
||||
from app.activitypub.signature import default_context, post_request_in_background
|
||||
from app.community.util import send_to_remote_instance
|
||||
from app.models import PostReply, User
|
||||
from app.models import PostReply, PostReplyBookmark, User
|
||||
from app.utils import gibberish, instance_banned, render_template, authorise_api_user, recently_upvoted_post_replies, recently_downvoted_post_replies
|
||||
|
||||
from flask import current_app, request
|
||||
from flask import abort, current_app, flash, redirect, request, url_for
|
||||
from flask_babel import _
|
||||
from flask_login import current_user
|
||||
|
||||
|
||||
|
@ -94,4 +95,66 @@ def vote_for_reply(reply_id: int, vote_direction, src, auth=None):
|
|||
community=reply.community)
|
||||
|
||||
|
||||
# function can be shared between WEB and API (only API calls it for now)
|
||||
# post_reply_bookmark in app/post/routes would just need to do 'return bookmark_the_post_reply(comment_id, SRC_WEB)'
|
||||
def bookmark_the_post_reply(comment_id: int, src, auth=None):
|
||||
if src == SRC_API and auth is not None:
|
||||
post_reply = PostReply.query.get(comment_id)
|
||||
if not post_reply or post_reply.deleted:
|
||||
raise Exception('comment_not_found')
|
||||
try:
|
||||
user_id = authorise_api_user(auth)
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
if post_reply.deleted:
|
||||
abort(404)
|
||||
user_id = current_user.id
|
||||
|
||||
existing_bookmark = PostReplyBookmark.query.filter(PostReplyBookmark.post_reply_id == comment_id,
|
||||
PostReplyBookmark.user_id == user_id).first()
|
||||
if not existing_bookmark:
|
||||
db.session.add(PostReplyBookmark(post_reply_id=comment_id, user_id=user_id))
|
||||
db.session.commit()
|
||||
if src == SRC_WEB:
|
||||
flash(_('Bookmark added.'))
|
||||
else:
|
||||
if src == SRC_WEB:
|
||||
flash(_('This comment has already been bookmarked'))
|
||||
|
||||
if src == SRC_API:
|
||||
return user_id
|
||||
else:
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post_reply.post_id, _anchor=f'comment_{comment_id}'))
|
||||
|
||||
|
||||
# function can be shared between WEB and API (only API calls it for now)
|
||||
# post_reply_remove_bookmark in app/post/routes would just need to do 'return remove_the_bookmark_from_post_reply(comment_id, SRC_WEB)'
|
||||
def remove_the_bookmark_from_post_reply(comment_id: int, src, auth=None):
|
||||
if src == SRC_API and auth is not None:
|
||||
post_reply = PostReply.query.get(comment_id)
|
||||
if not post_reply or post_reply.deleted:
|
||||
raise Exception('comment_not_found')
|
||||
try:
|
||||
user_id = authorise_api_user(auth)
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
if post_reply.deleted:
|
||||
abort(404)
|
||||
user_id = current_user.id
|
||||
|
||||
existing_bookmark = PostReplyBookmark.query.filter(PostReplyBookmark.post_reply_id == comment_id,
|
||||
PostReplyBookmark.user_id == user_id).first()
|
||||
if existing_bookmark:
|
||||
db.session.delete(existing_bookmark)
|
||||
db.session.commit()
|
||||
if src == SRC_WEB:
|
||||
flash(_('Bookmark has been removed.'))
|
||||
|
||||
if src == SRC_API:
|
||||
return user_id
|
||||
else:
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post_reply.post_id))
|
||||
|
|
Loading…
Reference in a new issue