mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
API: support /site/block endpoint
This commit is contained in:
parent
b49bb4cf3f
commit
d09c21a32e
9 changed files with 139 additions and 10 deletions
|
@ -1,5 +1,5 @@
|
||||||
from app.api.alpha import bp
|
from app.api.alpha import bp
|
||||||
from app.api.alpha.utils import get_site, \
|
from app.api.alpha.utils import get_site, post_site_block, \
|
||||||
get_search, \
|
get_search, \
|
||||||
get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe, \
|
get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe, \
|
||||||
get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, \
|
get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, \
|
||||||
|
@ -22,6 +22,18 @@ def get_alpha_site():
|
||||||
return jsonify({"error": str(ex)}), 400
|
return jsonify({"error": str(ex)}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/api/alpha/site/block', methods=['POST'])
|
||||||
|
def get_alpha_site_block():
|
||||||
|
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(post_site_block(auth, data))
|
||||||
|
except Exception as ex:
|
||||||
|
return jsonify({"error": str(ex)}), 400
|
||||||
|
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
@bp.route('/api/alpha/search', methods=['GET'])
|
@bp.route('/api/alpha/search', methods=['GET'])
|
||||||
def get_alpha_search():
|
def get_alpha_search():
|
||||||
|
@ -236,7 +248,6 @@ def post_alpha_user_block():
|
||||||
# Site - not yet implemented
|
# Site - not yet implemented
|
||||||
@bp.route('/api/alpha/site', methods=['POST'])
|
@bp.route('/api/alpha/site', methods=['POST'])
|
||||||
@bp.route('/api/alpha/site', methods=['PUT'])
|
@bp.route('/api/alpha/site', methods=['PUT'])
|
||||||
@bp.route('/api/alpha/site/block', methods=['POST'])
|
|
||||||
def alpha_site():
|
def alpha_site():
|
||||||
return jsonify({"error": "not_yet_implemented"}), 400
|
return jsonify({"error": "not_yet_implemented"}), 400
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from app.api.alpha.utils.site import get_site
|
from app.api.alpha.utils.site import get_site, post_site_block
|
||||||
from app.api.alpha.utils.misc import get_search
|
from app.api.alpha.utils.misc import get_search
|
||||||
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe
|
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe
|
||||||
from app.api.alpha.utils.reply import get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe
|
from app.api.alpha.utils.reply import get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe
|
||||||
|
|
|
@ -4,7 +4,7 @@ from app.api.alpha.utils.validators import required, integer_expected, boolean_e
|
||||||
from app.utils import authorise_api_user
|
from app.utils import authorise_api_user
|
||||||
from app.models import Community, CommunityMember
|
from app.models import Community, CommunityMember
|
||||||
from app.shared.community import join_community, leave_community, block_community, unblock_community
|
from app.shared.community import join_community, leave_community, block_community, unblock_community
|
||||||
from app.utils import communities_banned_from
|
from app.utils import communities_banned_from, blocked_instances
|
||||||
|
|
||||||
|
|
||||||
@cache.memoize(timeout=3)
|
@cache.memoize(timeout=3)
|
||||||
|
@ -17,6 +17,15 @@ def cached_community_list(type, user_id):
|
||||||
else:
|
else:
|
||||||
communities = Community.query.filter_by(banned=False)
|
communities = Community.query.filter_by(banned=False)
|
||||||
|
|
||||||
|
print(len(communities.all()))
|
||||||
|
|
||||||
|
if user_id is not None:
|
||||||
|
blocked_instance_ids = blocked_instances(user_id)
|
||||||
|
if blocked_instance_ids:
|
||||||
|
communities = communities.filter(Community.instance_id.not_in(blocked_instance_ids))
|
||||||
|
|
||||||
|
print(len(communities.all()))
|
||||||
|
|
||||||
return communities.all()
|
return communities.all()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from app.api.alpha.views import post_view
|
||||||
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected
|
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected
|
||||||
from app.models import Post, Community, CommunityMember, utcnow
|
from app.models import Post, Community, CommunityMember, utcnow
|
||||||
from app.shared.post import vote_for_post, bookmark_the_post, remove_the_bookmark_from_post, toggle_post_notification
|
from app.shared.post import vote_for_post, bookmark_the_post, remove_the_bookmark_from_post, toggle_post_notification
|
||||||
from app.utils import authorise_api_user, blocked_users, blocked_communities
|
from app.utils import authorise_api_user, blocked_users, blocked_communities, blocked_instances, community_ids_from_instances
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
@ -35,6 +35,10 @@ def cached_post_list(type, sort, user_id, community_id, community_name, person_i
|
||||||
blocked_community_ids = blocked_communities(user_id)
|
blocked_community_ids = blocked_communities(user_id)
|
||||||
if blocked_community_ids:
|
if blocked_community_ids:
|
||||||
posts = posts.filter(Post.community_id.not_in(blocked_community_ids))
|
posts = posts.filter(Post.community_id.not_in(blocked_community_ids))
|
||||||
|
blocked_instance_ids = blocked_instances(user_id)
|
||||||
|
if blocked_instance_ids:
|
||||||
|
posts = posts.filter(Post.instance_id.not_in(blocked_instance_ids)) # users from blocked instance
|
||||||
|
posts = posts.filter(Post.community_id.not_in(community_ids_from_instances(blocked_instance_ids))) # communities from blocked instance
|
||||||
|
|
||||||
if sort == "Hot":
|
if sort == "Hot":
|
||||||
posts = posts.order_by(desc(Post.ranking)).order_by(desc(Post.posted_at))
|
posts = posts.order_by(desc(Post.ranking)).order_by(desc(Post.posted_at))
|
||||||
|
|
|
@ -3,7 +3,7 @@ from app.api.alpha.utils.validators import required, integer_expected, boolean_e
|
||||||
from app.api.alpha.views import reply_view
|
from app.api.alpha.views import reply_view
|
||||||
from app.models import PostReply
|
from app.models import PostReply
|
||||||
from app.shared.reply import vote_for_reply, bookmark_the_post_reply, remove_the_bookmark_from_post_reply, toggle_post_reply_notification
|
from app.shared.reply import vote_for_reply, bookmark_the_post_reply, remove_the_bookmark_from_post_reply, toggle_post_reply_notification
|
||||||
from app.utils import authorise_api_user, blocked_users
|
from app.utils import authorise_api_user, blocked_users, blocked_instances
|
||||||
|
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ def cached_reply_list(post_id, person_id, sort, max_depth, user_id):
|
||||||
blocked_person_ids = blocked_users(user_id)
|
blocked_person_ids = blocked_users(user_id)
|
||||||
if blocked_person_ids:
|
if blocked_person_ids:
|
||||||
replies = replies.filter(PostReply.user_id.not_in(blocked_person_ids))
|
replies = replies.filter(PostReply.user_id.not_in(blocked_person_ids))
|
||||||
|
blocked_instance_ids = blocked_instances(user_id)
|
||||||
|
if blocked_instance_ids:
|
||||||
|
replies = replies.filter(PostReply.instance_id.not_in(blocked_instance_ids))
|
||||||
|
|
||||||
if sort == "Hot":
|
if sort == "Hot":
|
||||||
replies = replies.order_by(desc(PostReply.ranking)).order_by(desc(PostReply.posted_at))
|
replies = replies.order_by(desc(PostReply.ranking)).order_by(desc(PostReply.posted_at))
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from app import db
|
from app import db
|
||||||
from app.api.alpha.views import user_view, community_view
|
from app.api.alpha.views import user_view, community_view, instance_view
|
||||||
|
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected
|
||||||
from app.utils import authorise_api_user
|
from app.utils import authorise_api_user
|
||||||
from app.models import Language
|
from app.models import InstanceBlock, Language
|
||||||
|
from app.shared.site import block_remote_instance, unblock_remote_instance
|
||||||
|
|
||||||
from flask import current_app, g
|
from flask import current_app, g
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@ def get_site(auth):
|
||||||
#"moderates": [],
|
#"moderates": [],
|
||||||
#"follows": [],
|
#"follows": [],
|
||||||
"community_blocks": [],
|
"community_blocks": [],
|
||||||
"instance_blocks": [], # TODO
|
"instance_blocks": [],
|
||||||
"person_blocks": [],
|
"person_blocks": [],
|
||||||
"discussion_languages": [] # TODO
|
"discussion_languages": [] # TODO
|
||||||
}
|
}
|
||||||
|
@ -87,6 +89,9 @@ def get_site(auth):
|
||||||
blocked_ids = db.session.execute(text('SELECT community_id FROM "community_block" WHERE user_id = :user_id'), {"user_id": user.id}).scalars()
|
blocked_ids = db.session.execute(text('SELECT community_id FROM "community_block" WHERE user_id = :user_id'), {"user_id": user.id}).scalars()
|
||||||
for blocked_id in blocked_ids:
|
for blocked_id in blocked_ids:
|
||||||
my_user['community_blocks'].append({'person': user_view(user, variant=1, stub=True), 'community': community_view(blocked_id, variant=1, stub=True)})
|
my_user['community_blocks'].append({'person': user_view(user, variant=1, stub=True), 'community': community_view(blocked_id, variant=1, stub=True)})
|
||||||
|
blocked_ids = db.session.execute(text('SELECT instance_id FROM "instance_block" WHERE user_id = :user_id'), {"user_id": user.id}).scalars()
|
||||||
|
for blocked_id in blocked_ids:
|
||||||
|
my_user['instance_blocks'].append({'person': user_view(user, variant=1, stub=True), 'instance': instance_view(blocked_id, variant=1)})
|
||||||
data = {
|
data = {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"site": site
|
"site": site
|
||||||
|
@ -96,3 +101,21 @@ def get_site(auth):
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
SRC_API = 3
|
||||||
|
|
||||||
|
def post_site_block(auth, data):
|
||||||
|
required(['instance_id', 'block'], data)
|
||||||
|
integer_expected(['instance_id'], data)
|
||||||
|
boolean_expected(['block'], data)
|
||||||
|
|
||||||
|
instance_id = data['instance_id']
|
||||||
|
block = data['block']
|
||||||
|
|
||||||
|
user_id = block_remote_instance(instance_id, SRC_API, auth) if block else unblock_remote_instance(instance_id, SRC_API, auth)
|
||||||
|
blocked = InstanceBlock.query.filter_by(user_id=user_id, instance_id=instance_id).first()
|
||||||
|
block = True if blocked else False
|
||||||
|
data = {
|
||||||
|
"blocked": block
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from app import cache, db
|
from app import cache, db
|
||||||
from app.constants import *
|
from app.constants import *
|
||||||
from app.models import Community, CommunityMember, Post, PostReply, PostVote, User
|
from app.models import Community, CommunityMember, Instance, Post, PostReply, PostVote, User
|
||||||
from app.utils import blocked_communities
|
from app.utils import blocked_communities
|
||||||
|
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
@ -343,6 +343,22 @@ def search_view(type):
|
||||||
return v1
|
return v1
|
||||||
|
|
||||||
|
|
||||||
|
def instance_view(instance: Instance | int, variant):
|
||||||
|
if isinstance(instance, int):
|
||||||
|
instance = Instance.query.get(instance)
|
||||||
|
if not instance:
|
||||||
|
raise Exception('instance_not_found')
|
||||||
|
|
||||||
|
if variant == 1:
|
||||||
|
include = ['id', 'domain', 'software', 'version']
|
||||||
|
v1 = {column.name: getattr(instance, column.name) for column in instance.__table__.columns if column.name in include}
|
||||||
|
if not v1['version']:
|
||||||
|
v1.update({'version': '0.0.1'})
|
||||||
|
v1.update({'published': instance.created_at.isoformat() + 'Z', 'updated': instance.updated_at.isoformat() + 'Z'})
|
||||||
|
|
||||||
|
return v1
|
||||||
|
|
||||||
|
|
||||||
@cache.memoize(timeout=86400)
|
@cache.memoize(timeout=86400)
|
||||||
def cached_modlist_for_community(community_id):
|
def cached_modlist_for_community(community_id):
|
||||||
moderator_ids = db.session.execute(text('SELECT user_id FROM "community_member" WHERE community_id = :community_id and is_moderator = True'), {'community_id': community_id}).scalars()
|
moderator_ids = db.session.execute(text('SELECT user_id FROM "community_member" WHERE community_id = :community_id and is_moderator = True'), {'community_id': community_id}).scalars()
|
||||||
|
|
57
app/shared/site.py
Normal file
57
app/shared/site.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from app import cache, db
|
||||||
|
from app.models import InstanceBlock
|
||||||
|
from app.utils import authorise_api_user, blocked_instances
|
||||||
|
|
||||||
|
from flask import flash
|
||||||
|
from flask_babel import _
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
|
# would be in app/constants.py
|
||||||
|
SRC_WEB = 1
|
||||||
|
SRC_PUB = 2
|
||||||
|
SRC_API = 3
|
||||||
|
|
||||||
|
|
||||||
|
def block_remote_instance(instance_id, src, auth=None):
|
||||||
|
if src == SRC_API:
|
||||||
|
user_id = authorise_api_user(auth)
|
||||||
|
else:
|
||||||
|
user_id = current_user.id
|
||||||
|
|
||||||
|
if instance_id == 1:
|
||||||
|
if src == SRC_API:
|
||||||
|
raise Exception('cannot_block_local_instance')
|
||||||
|
else:
|
||||||
|
flash(_('You cannot block the local instance.'), 'error')
|
||||||
|
return
|
||||||
|
|
||||||
|
existing = InstanceBlock.query.filter_by(user_id=user_id, instance_id=instance_id).first()
|
||||||
|
if not existing:
|
||||||
|
db.session.add(InstanceBlock(user_id=user_id, instance_id=instance_id))
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
cache.delete_memoized(blocked_instances, user_id)
|
||||||
|
|
||||||
|
if src == SRC_API:
|
||||||
|
return user_id
|
||||||
|
else:
|
||||||
|
return # let calling function handle confirmation flash message and redirect
|
||||||
|
|
||||||
|
|
||||||
|
def unblock_remote_instance(instance_id, src, auth=None):
|
||||||
|
if src == SRC_API:
|
||||||
|
user_id = authorise_api_user(auth)
|
||||||
|
else:
|
||||||
|
user_id = current_user.id
|
||||||
|
|
||||||
|
existing = InstanceBlock.query.filter_by(user_id=user_id, instance_id=instance_id).first()
|
||||||
|
if existing:
|
||||||
|
db.session.delete(existing)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
cache.delete_memoized(blocked_instances, user_id)
|
||||||
|
|
||||||
|
if src == SRC_API:
|
||||||
|
return user_id
|
||||||
|
else:
|
||||||
|
return # let calling function handle confirmation flash message and redirect
|
|
@ -1301,3 +1301,9 @@ def authorise_api_user(auth, return_type='id'):
|
||||||
raise Exception('incorrect_login')
|
raise Exception('incorrect_login')
|
||||||
except jwt.InvalidTokenError:
|
except jwt.InvalidTokenError:
|
||||||
raise Exception('invalid_token')
|
raise Exception('invalid_token')
|
||||||
|
|
||||||
|
|
||||||
|
@cache.memoize(timeout=86400)
|
||||||
|
def community_ids_from_instances(instance_ids) -> List[int]:
|
||||||
|
communities = Community.query.join(Instance, Instance.id == Community.instance_id).filter(Instance.id.in_(instance_ids))
|
||||||
|
return [community.id for community in communities]
|
||||||
|
|
Loading…
Reference in a new issue