mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-24 11:51:27 -08:00
165 lines
5.4 KiB
Python
165 lines
5.4 KiB
Python
from app import cache, celery, db
|
|
from app.activitypub.signature import default_context, post_request
|
|
from app.models import Community, CommunityBan, CommunityJoinRequest, User
|
|
from app.utils import community_membership, gibberish, joined_communities, instance_banned
|
|
|
|
from flask import current_app, flash
|
|
from flask_babel import _
|
|
|
|
|
|
# would be in app/constants.py
|
|
SRC_WEB = 1
|
|
SRC_PUB = 2
|
|
SRC_API = 3
|
|
SRC_PLD = 4
|
|
|
|
|
|
""" JSON format
|
|
{
|
|
'id':
|
|
'type':
|
|
'actor':
|
|
'object':
|
|
'@context': (outer object only)
|
|
'to': []
|
|
}
|
|
"""
|
|
|
|
"""
|
|
async:
|
|
delete memoized
|
|
add or delete community_join_request
|
|
used for admin preload in production (return values are ignored)
|
|
used for API
|
|
sync:
|
|
add or delete community_member
|
|
used for debug mode
|
|
used for web users to provide feedback
|
|
"""
|
|
|
|
|
|
@celery.task
|
|
def join_community(send_async, user_id, community_id, src):
|
|
user = User.query.filter_by(id=user_id).one()
|
|
community = Community.query.filter_by(id=community_id).one()
|
|
|
|
pre_load_message = {}
|
|
banned = CommunityBan.query.filter_by(user_id=user_id, community_id=community_id).first()
|
|
if banned:
|
|
if not send_async:
|
|
if src == SRC_WEB:
|
|
flash(_('You cannot join this community'))
|
|
return
|
|
elif src == SRC_PLD:
|
|
pre_load_message['user_banned'] = True
|
|
return pre_load_message
|
|
elif src == SRC_API:
|
|
raise Exception('banned_from_community')
|
|
return
|
|
|
|
if (not community.is_local() and
|
|
(user.has_blocked_instance(community.instance.id) or
|
|
instance_banned(community.instance.domain))):
|
|
if not send_async:
|
|
if src == SRC_WEB:
|
|
flash(_('Community is on banned or blocked instance'))
|
|
return
|
|
elif src == SRC_PLD:
|
|
pre_load_message['community_on_banned_or_blocked_instance'] = True
|
|
return pre_load_message
|
|
elif src == SRC_API:
|
|
raise Exception('community_on_banned_or_blocked_instance')
|
|
return
|
|
|
|
success = True
|
|
if not community.is_local() and community.instance.online():
|
|
join_request = CommunityJoinRequest(user_id=user_id, community_id=community_id)
|
|
db.session.add(join_request)
|
|
db.session.commit()
|
|
|
|
follow_id = f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request.id}"
|
|
follow = {
|
|
'id': follow_id,
|
|
'type': 'Follow',
|
|
'actor': user.public_url(),
|
|
'object': community.public_url(),
|
|
'@context': default_context(),
|
|
'to': [community.public_url()],
|
|
}
|
|
success = post_request(community.ap_inbox_url, follow, user.private_key,
|
|
user.public_url() + '#main-key', timeout=10)
|
|
if success is False or isinstance(success, str):
|
|
if not send_async:
|
|
db.session.query(CommunityJoinRequest).filter_by(user_id=user_id, community_id=community_id).delete()
|
|
db.session.commit()
|
|
|
|
if 'is not in allowlist' in success:
|
|
msg_to_user = f'{community.instance.domain} does not allow us to join their communities.'
|
|
else:
|
|
msg_to_user = "There was a problem while trying to communicate with remote server. Please try again later."
|
|
|
|
if src == SRC_WEB:
|
|
flash(_(msg_to_user), 'error')
|
|
return
|
|
elif src == SRC_PLD:
|
|
pre_load_message['status'] = msg_to_user
|
|
return pre_load_message
|
|
elif src == SRC_API:
|
|
raise Exception(msg_to_user)
|
|
|
|
# for communities on local or offline instances, joining is instant
|
|
if success is True:
|
|
cache.delete_memoized(community_membership, user, community)
|
|
cache.delete_memoized(joined_communities, user.id)
|
|
|
|
if src == SRC_WEB:
|
|
flash('You joined ' + community.title)
|
|
return
|
|
elif src == SRC_PLD:
|
|
pre_load_message['status'] = 'joined'
|
|
return pre_load_message
|
|
|
|
return success
|
|
|
|
|
|
@celery.task
|
|
def leave_community(send_async, user_id, community_id):
|
|
user = User.query.filter_by(id=user_id).one()
|
|
community = Community.query.filter_by(id=community_id).one()
|
|
|
|
cache.delete_memoized(community_membership, user, community)
|
|
cache.delete_memoized(joined_communities, user.id)
|
|
|
|
if community.is_local():
|
|
return
|
|
|
|
join_request = CommunityJoinRequest.query.filter_by(user_id=user_id, community_id=community_id).one()
|
|
db.session.delete(join_request)
|
|
db.session.commit()
|
|
|
|
if (not community.instance.online() or
|
|
user.has_blocked_instance(community.instance.id) or
|
|
instance_banned(community.instance.domain)):
|
|
return
|
|
|
|
follow_id = f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request.id}"
|
|
follow = {
|
|
'id': follow_id,
|
|
'type': 'Follow',
|
|
'actor': user.public_url(),
|
|
'object': community.public_url(),
|
|
'to': [community.public_url()]
|
|
}
|
|
undo_id = f"https://{current_app.config['SERVER_NAME']}/activities/undo/{gibberish(15)}"
|
|
undo = {
|
|
'id': undo_id,
|
|
'type': 'Undo',
|
|
'actor': user.public_url(),
|
|
'object': follow,
|
|
'@context': default_context(),
|
|
'to': [community.public_url()]
|
|
}
|
|
|
|
post_request(community.ap_inbox_url, undo, user.private_key, user.public_url() + '#main-key', timeout=10)
|
|
|
|
|