mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
import community subscriptions from lemmy
This commit is contained in:
parent
47cdf79b20
commit
cd4fa6ad25
8 changed files with 119 additions and 17 deletions
|
@ -391,7 +391,7 @@ def actor_json_to_model(activity_json, address, server):
|
|||
private_mods=activity_json['privateMods'] if 'privateMods' in activity_json else False,
|
||||
created_at=activity_json['published'] if 'published' in activity_json else utcnow(),
|
||||
last_active=activity_json['updated'] if 'updated' in activity_json else utcnow(),
|
||||
ap_id=f"{address[1:]}",
|
||||
ap_id=f"{address[1:]}@{server}" if address.startswith('!') else f"{address}@{server}",
|
||||
ap_public_url=activity_json['id'],
|
||||
ap_profile_id=activity_json['id'],
|
||||
ap_followers_url=activity_json['followers'],
|
||||
|
|
|
@ -291,6 +291,7 @@ def unsubscribe_everyone_then_delete_task(community_id):
|
|||
sleep(5)
|
||||
community.delete_dependencies()
|
||||
db.session.delete(community) # todo: when a remote community is deleted it will be able to be re-created by using the 'Add remote' function. Not ideal. Consider soft-delete.
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@bp.route('/topics', methods=['GET'])
|
||||
|
|
|
@ -230,11 +230,13 @@ def subscribe(actor):
|
|||
banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first()
|
||||
if banned:
|
||||
flash('You cannot join this community')
|
||||
member = CommunityMember(user_id=current_user.id, community_id=community.id)
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
flash('You joined ' + community.title)
|
||||
else:
|
||||
member = CommunityMember(user_id=current_user.id, community_id=community.id)
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
flash('You joined ' + community.title)
|
||||
referrer = request.headers.get('Referer', None)
|
||||
cache.delete_memoized(community_membership, current_user, community)
|
||||
if referrer is not None:
|
||||
return redirect(referrer)
|
||||
else:
|
||||
|
|
|
@ -53,7 +53,7 @@ def search_for_community(address: str):
|
|||
community_json = community_data.json()
|
||||
community_data.close()
|
||||
if community_json['type'] == 'Group':
|
||||
community = actor_json_to_model(community_json, address, server)
|
||||
community = actor_json_to_model(community_json, name, server)
|
||||
if current_app.debug:
|
||||
retrieve_mods_and_backfill(community.id)
|
||||
else:
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="card-title">{{ _('Found a community:') }}</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
<a href="/c/{{ new_community.link() }}"><img src="{{ new_community.icon_image()}}" class="community_icon rounded-circle" /></a>
|
||||
<a href="/c/{{ new_community.link() }}"><img src="{{ new_community.icon_image()}}" class="community_icon rounded-circle" style="width: 30px; vertical-align: middle;" /></a>
|
||||
<a href="/c/{{ new_community.link() }}">{{ new_community.title }}@{{ new_community.ap_domain }}</a>
|
||||
</p>
|
||||
<p> {% if subscribed %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% from 'bootstrap/form.html' import render_form %}
|
||||
{% from 'bootstrap/form.html' import render_field %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
|
@ -12,8 +12,16 @@
|
|||
</ol>
|
||||
</nav>
|
||||
<h1 class="mt-2">{{ _('Change settings') }}</h1>
|
||||
<form method='post'>
|
||||
{{ render_form(form) }}
|
||||
<form method='post' enctype="multipart/form-data">
|
||||
{{ form.csrf_token() }}
|
||||
{{ render_field(form.newsletter) }}
|
||||
{{ render_field(form.ignore_bots) }}
|
||||
{{ render_field(form.nsfw) }}
|
||||
{{ render_field(form.nsfl) }}
|
||||
{{ render_field(form.searchable) }}
|
||||
{{ render_field(form.indexable) }}
|
||||
{{ render_field(form.import_file) }}
|
||||
{{ render_field(form.submit) }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,6 +33,7 @@ class SettingsForm(FlaskForm):
|
|||
searchable = BooleanField(_l('Show profile in user list'))
|
||||
indexable = BooleanField(_l('Allow search engines to index this profile'))
|
||||
manually_approves_followers = BooleanField(_l('Manually approve followers'))
|
||||
import_file = FileField(_('Import community subscriptions and user blocks from Lemmy'))
|
||||
submit = SubmitField(_l('Save settings'))
|
||||
|
||||
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
from datetime import datetime, timedelta
|
||||
from time import sleep
|
||||
|
||||
from flask import redirect, url_for, flash, request, make_response, session, Markup, current_app, abort
|
||||
from flask import redirect, url_for, flash, request, make_response, session, Markup, current_app, abort, json
|
||||
from flask_login import login_user, logout_user, current_user, login_required
|
||||
from flask_babel import _
|
||||
|
||||
from app import db, cache, celery
|
||||
from app.activitypub.signature import post_request
|
||||
from app.activitypub.util import default_context
|
||||
from app.community.util import save_icon_file, save_banner_file
|
||||
from app.activitypub.util import default_context, find_actor_or_create
|
||||
from app.community.util import save_icon_file, save_banner_file, retrieve_mods_and_backfill
|
||||
from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_PENDING
|
||||
from app.models import Post, Community, CommunityMember, User, PostReply, PostVote, Notification, utcnow, File, Site, \
|
||||
Instance, Report, UserBlock
|
||||
Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock
|
||||
from app.user import bp
|
||||
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm
|
||||
from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string, \
|
||||
is_image_url
|
||||
is_image_url, ensure_directory_exists, gibberish, file_get_contents, community_membership
|
||||
from sqlalchemy import desc, or_, text
|
||||
import os
|
||||
|
||||
|
||||
@bp.route('/people', methods=['GET', 'POST'])
|
||||
|
@ -142,7 +144,24 @@ def change_settings(actor):
|
|||
current_user.show_nsfl = form.nsfl.data
|
||||
current_user.searchable = form.searchable.data
|
||||
current_user.indexable = form.indexable.data
|
||||
current_user.ap_manually_approves_followers = form.manually_approves_followers.data
|
||||
import_file = request.files['import_file']
|
||||
if import_file and import_file.filename != '':
|
||||
file_ext = os.path.splitext(import_file.filename)[1]
|
||||
if file_ext.lower() != '.json':
|
||||
abort(400)
|
||||
new_filename = gibberish(15) + '.json'
|
||||
|
||||
directory = f'app/static/media/'
|
||||
|
||||
# save the file
|
||||
final_place = os.path.join(directory, new_filename + file_ext)
|
||||
import_file.save(final_place)
|
||||
|
||||
# import settings in background task
|
||||
import_settings(final_place)
|
||||
|
||||
flash(_('Your subscriptions and blocks are being imported. If you have many it could take a few minutes.'))
|
||||
|
||||
db.session.commit()
|
||||
|
||||
flash(_('Your changes have been saved.'), 'success')
|
||||
|
@ -154,7 +173,6 @@ def change_settings(actor):
|
|||
form.nsfl.data = current_user.show_nsfl
|
||||
form.searchable.data = current_user.searchable
|
||||
form.indexable.data = current_user.indexable
|
||||
form.manually_approves_followers.data = current_user.ap_manually_approves_followers
|
||||
|
||||
return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user)
|
||||
|
||||
|
@ -475,3 +493,75 @@ def notifications_all_read():
|
|||
db.session.commit()
|
||||
flash(_('All notifications marked as read.'))
|
||||
return redirect(url_for('user.notifications'))
|
||||
|
||||
|
||||
def import_settings(filename):
|
||||
if current_app.debug:
|
||||
import_settings_task(current_user.id, filename)
|
||||
else:
|
||||
import_settings_task.delay(current_user.id, filename)
|
||||
|
||||
|
||||
@celery.task
|
||||
def import_settings_task(user_id, filename):
|
||||
user = User.query.get(user_id)
|
||||
contents = file_get_contents(filename)
|
||||
contents_json = json.loads(contents)
|
||||
|
||||
# Follow communities
|
||||
for community_ap_id in contents_json['followed_communities'] if 'followed_communities' in contents_json else []:
|
||||
community = find_actor_or_create(community_ap_id)
|
||||
if community:
|
||||
if community.posts.count() == 0:
|
||||
if current_app.debug:
|
||||
retrieve_mods_and_backfill(community.id)
|
||||
else:
|
||||
retrieve_mods_and_backfill.delay(community.id)
|
||||
if community_membership(user, community) != SUBSCRIPTION_MEMBER and community_membership(
|
||||
user, community) != SUBSCRIPTION_PENDING:
|
||||
if not community.is_local():
|
||||
# send ActivityPub message to remote community, asking to follow. Accept message will be sent to our shared inbox
|
||||
join_request = CommunityJoinRequest(user_id=user.id, community_id=community.id)
|
||||
db.session.add(join_request)
|
||||
db.session.commit()
|
||||
follow = {
|
||||
"actor": f"https://{current_app.config['SERVER_NAME']}/u/{user.user_name}",
|
||||
"to": [community.ap_profile_id],
|
||||
"object": community.ap_profile_id,
|
||||
"type": "Follow",
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request.id}"
|
||||
}
|
||||
success = post_request(community.ap_inbox_url, follow, user.private_key,
|
||||
user.profile_id() + '#main-key')
|
||||
if not success:
|
||||
sleep(5) # give them a rest
|
||||
else: # for local communities, joining is instant
|
||||
banned = CommunityBan.query.filter_by(user_id=user.id, community_id=community.id).first()
|
||||
if not banned:
|
||||
member = CommunityMember(user_id=user.id, community_id=community.id)
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
cache.delete_memoized(community_membership, current_user, community)
|
||||
|
||||
for community_ap_id in contents_json['blocked_communities'] if 'blocked_communities' in contents_json else []:
|
||||
community = find_actor_or_create(community_ap_id)
|
||||
if community:
|
||||
existing_block = CommunityBlock.query.filter_by(user_id=user.id, community_id=community.id).first()
|
||||
if not existing_block:
|
||||
block = CommunityBlock(user_id=user.id, community_id=community.id)
|
||||
db.session.add(block)
|
||||
|
||||
for user_ap_id in contents_json['blocked_users'] if 'blocked_users' in contents_json else []:
|
||||
blocked_user = find_actor_or_create(user_ap_id)
|
||||
if blocked_user:
|
||||
existing_block = UserBlock.query.filter_by(blocker_id=user.id, blocked_id=blocked_user.id).first()
|
||||
if not existing_block:
|
||||
user_block = UserBlock(blocker_id=user.id, blocked_id=blocked_user.id)
|
||||
db.session.add(user_block)
|
||||
if not blocked_user.is_local():
|
||||
... # todo: federate block
|
||||
|
||||
for instance_domain in contents_json['blocked_instances']:
|
||||
...
|
||||
|
||||
db.session.commit()
|
||||
|
|
Loading…
Add table
Reference in a new issue