From 3838ad57015c49277292d01d8f0c9c721d08f6c1 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Wed, 11 Sep 2024 19:14:12 -0400 Subject: [PATCH 01/12] Adding a pre-load of threadiverse communities to the admin area --- app/admin/forms.py | 2 ++ app/admin/routes.py | 12 +++++++++--- app/templates/admin/federation.html | 7 +++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/admin/forms.py b/app/admin/forms.py index 1a1d649d..62ce7c96 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -51,6 +51,8 @@ class FederationForm(FlaskForm): blocked_actors = TextAreaField(_l('Discard all posts and comments by users with these words in their name (one per line)')) submit = SubmitField(_l('Save')) +class PreLoadCommunitiesForm(FlaskForm): + pre_load_submit = SubmitField(_l('Add Communities')) class EditCommunityForm(FlaskForm): title = StringField(_l('Title'), validators=[DataRequired()]) diff --git a/app/admin/routes.py b/app/admin/routes.py index 15312b04..bb4412ce 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -15,7 +15,7 @@ from app.activitypub.routes import process_inbox_request, process_delete_request from app.activitypub.signature import post_request, default_context from app.activitypub.util import instance_allowed, instance_blocked from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \ - EditTopicForm, SendNewsletterForm, AddUserForm + EditTopicForm, SendNewsletterForm, AddUserForm, PreLoadCommunitiesForm from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter, \ topics_for_form from app.community.util import save_icon_file, save_banner_file @@ -190,12 +190,17 @@ def admin_misc(): @permission_required('change instance settings') def admin_federation(): form = FederationForm() + preload_form = PreLoadCommunitiesForm() site = Site.query.get(1) if site is None: site = Site() # todo: finish form site.updated = utcnow() - if form.validate_on_submit(): + if preload_form.pre_load_submit.data and preload_form.validate(): + flash(_('add communities button clicked')) + return redirect(url_for('admin.admin_federation')) + + elif form.validate_on_submit(): if form.use_allowlist.data: set_setting('use_allowlist', True) db.session.execute(text('DELETE FROM allowed_instances')) @@ -228,7 +233,8 @@ def admin_federation(): form.blocked_phrases.data = site.blocked_phrases form.blocked_actors.data = get_setting('actor_blocked_words', '88') - return render_template('admin/federation.html', title=_('Federation settings'), form=form, + return render_template('admin/federation.html', title=_('Federation settings'), + form=form, preload_form=preload_form, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()), menu_topics=menu_topics(), diff --git a/app/templates/admin/federation.html b/app/templates/admin/federation.html index d41cebcf..d3cf0f4e 100644 --- a/app/templates/admin/federation.html +++ b/app/templates/admin/federation.html @@ -15,6 +15,13 @@
+
+
+

Use this to "pre-load" the top 50 known threadiverse communities, as rnaked by posts and activity. The list of communities pulls from the same list as LemmyVerse. NSFW communities and communities from banned instances are excluded.

+ {{ render_form(preload_form) }} +
+
+
{% include 'admin/_nav.html' %} From badf4cddba6101515af1bafaef4ffd6c11e855c2 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Thu, 12 Sep 2024 12:56:09 -0400 Subject: [PATCH 02/12] got the top 25 sorting for pre-load function to work --- app/admin/routes.py | 88 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/app/admin/routes.py b/app/admin/routes.py index bb4412ce..fb3b1788 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -1,6 +1,7 @@ import os from datetime import datetime, timedelta from io import BytesIO +import requests as r from time import sleep from flask import request, flash, json, url_for, current_app, redirect, g, abort @@ -196,10 +197,88 @@ def admin_federation(): site = Site() # todo: finish form site.updated = utcnow() - if preload_form.pre_load_submit.data and preload_form.validate(): - flash(_('add communities button clicked')) - return redirect(url_for('admin.admin_federation')) + # this is the pre-load communities button + if preload_form.pre_load_submit.data and preload_form.validate(): + # var - how many communities to add, hard-coded to 20 for now, can be made editable later + communities_to_add = 25 + + # pull down the community.full.json + resp = r.get('https://data.lemmyverse.net/data/community.full.json') + + # asign the json from the response to a var + cfj = resp.json() + + # sort out the nsfw communities + csfw = [] + for c in cfj: + if c['nsfw']: + continue + else: + csfw.append(c) + + # sort out any that have less than 100 posts + cplt100 = [] + for c in csfw: + if c['counts']['posts'] < 100: + continue + else: + cplt100.append(c) + + # sort out any that do not have greater than 500 active users over the past week + cuawgt500 = [] + for c in cplt100: + if c['counts']['users_active_week'] < 500: + continue + else: + cuawgt500.append(c) + + # sort out any instances we have already banned + banned_instances = BannedInstances.query.all() + banned_urls = [] + cnotbanned = [] + for bi in banned_instances: + banned_urls.append(bi.domain) + for c in cuawgt500: + if c['baseurl'] in banned_urls: + continue + else: + cnotbanned.append(c) + + # sort out the 'seven things you can't say on tv' names (cursewords, ie sh*t), plus some + # "low effort" communities + # I dont know why, but some of them slip through on the first pass, so I just + # ran the list again and filter out more + # + # TO-DO: fix the need for the double filter + seven_things_plus = [ + 'shit', 'piss', 'fuck', + 'cunt', 'cocksucker', 'motherfucker', 'tits', + 'memes', 'piracy', '196', 'greentext', 'usauthoritarianism', + 'enoughmuskspam', 'political_weirdos' + ] + for c in cnotbanned: + for w in seven_things_plus: + if w in c['name']: + cnotbanned.remove(c) + for c in cnotbanned: + for w in seven_things_plus: + if w in c['name']: + cnotbanned.remove(c) + + # sort the list based on the users_active_week key + parsed_communities_sorted = sorted(cnotbanned, key=lambda c: c['counts']['users_active_week'], reverse=True) + + # testing - print the top 20 in the list to a flash + top_20 = [] + for i in range(communities_to_add): + top_20.append(parsed_communities_sorted[i]['url']) + + flash(_(f'top_20 == {top_20}')) + # flash(_(f'leng_before == {leng_before}, leng_middle == {leng_middle}, leng_after == {leng_after}')) + return redirect(url_for('admin.admin_federation')) + + # this is the main settings form elif form.validate_on_submit(): if form.use_allowlist.data: set_setting('use_allowlist', True) @@ -222,7 +301,8 @@ def admin_federation(): db.session.commit() flash(_('Admin settings saved')) - + + # this is just the regular page load elif request.method == 'GET': form.use_allowlist.data = get_setting('use_allowlist', False) form.use_blocklist.data = not form.use_allowlist.data From f00a9b27225335a923cfe5a2938f864b2f80b097 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Thu, 12 Sep 2024 14:45:38 -0400 Subject: [PATCH 03/12] initial pass at the subscribe step --- app/admin/routes.py | 24 +++++++++++++++---- app/community/routes.py | 53 +++++++++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/app/admin/routes.py b/app/admin/routes.py index fb3b1788..c75ec433 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -14,12 +14,13 @@ from PIL import Image from app import db, celery, cache from app.activitypub.routes import process_inbox_request, process_delete_request from app.activitypub.signature import post_request, default_context -from app.activitypub.util import instance_allowed, instance_blocked +from app.activitypub.util import instance_allowed, instance_blocked, extract_domain_and_actor from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \ EditTopicForm, SendNewsletterForm, AddUserForm, PreLoadCommunitiesForm from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter, \ topics_for_form -from app.community.util import save_icon_file, save_banner_file +from app.community.util import save_icon_file, save_banner_file, search_for_community +from app.community.routes import do_subscribe from app.constants import REPORT_STATE_NEW, REPORT_STATE_ESCALATED from app.email import send_welcome_email from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow, Site, Community, CommunityMember, \ @@ -269,10 +270,23 @@ def admin_federation(): # sort the list based on the users_active_week key parsed_communities_sorted = sorted(cnotbanned, key=lambda c: c['counts']['users_active_week'], reverse=True) - # testing - print the top 20 in the list to a flash - top_20 = [] + # get the community urls to join + community_urls_to_join = [] for i in range(communities_to_add): - top_20.append(parsed_communities_sorted[i]['url']) + community_urls_to_join.append(parsed_communities_sorted[i]['url']) + + # loop through the list and send off the follow requests + pre_load_messages = [] + for c in community_urls_to_join: + # get the relevant url bits + server, community = extract_domain_and_actor(c) + # find the community + new_community = search_for_community('!' + community + '@' + server) + # subscribe to the community + # since this is using the alt_user_name, capture the messages + # returned by do_subscibe as well + message = do_subscribe(new_community.ap_id, main_user_name=False) + flash(_(f'top_20 == {top_20}')) # flash(_(f'leng_before == {leng_before}, leng_middle == {leng_middle}, leng_after == {leng_after}')) diff --git a/app/community/routes.py b/app/community/routes.py index 465b9880..d34dc10c 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -390,8 +390,14 @@ def show_community_rss(actor): @login_required @validation_required def subscribe(actor): + do_subscribe(actor) + +# this is separated out from the route, so it can be used by the +# admin.admin_federation.preload_form as well +def do_subscribe(actor, main_user_name=True): remote = False actor = actor.strip() + pre_load_message = {} if '@' in actor: community = Community.query.filter_by(banned=False, ap_id=actor).first() remote = True @@ -399,12 +405,19 @@ def subscribe(actor): community = Community.query.filter_by(name=actor, banned=False, ap_id=None).first() if community is not None: + pre_load_message['community'] = community.ap_id if community.id in communities_banned_from(current_user.id): - abort(401) + if main_user_name: + abort(401) + else: + pre_load_message['user_banned'] = True if community_membership(current_user, community) != SUBSCRIPTION_MEMBER and community_membership(current_user, community) != SUBSCRIPTION_PENDING: banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first() if banned: - flash(_('You cannot join this community')) + if main_user_name: + flash(_('You cannot join this community')) + else: + pre_load_message['community_banned_by_local_instance'] = True success = True if remote: # send ActivityPub message to remote community, asking to follow. Accept message will be sent to our shared inbox @@ -413,7 +426,7 @@ def subscribe(actor): db.session.commit() if community.instance.online(): follow = { - "actor": current_user.public_url(), + "actor": current_user.public_url(main_user_name=main_user_name), "to": [community.public_url()], "object": community.public_url(), "type": "Follow", @@ -423,24 +436,44 @@ def subscribe(actor): current_user.public_url() + '#main-key', timeout=10) if success is False or isinstance(success, str): if 'is not in allowlist' in success: - flash(_('%(name)s does not allow us to join their communities.', name=community.instance.domain), 'error') + msg_to_user = f'{community.instance.domain} does not allow us to join their communities.' + if main_user_name: + flash(_(msg_to_user), 'error') + else: + pre_load_message['status'] = msg_to_user else: - flash(_("There was a problem while trying to communicate with remote server. If other people have already joined this community it won't matter."), 'error') + msg_to_user = "There was a problem while trying to communicate with remote server. If other people have already joined this community it won't matter." + if main_user_name: + flash(_(msg_to_user), 'error') + else: + pre_load_message['status'] = msg_to_user + # for local communities, joining is instant member = CommunityMember(user_id=current_user.id, community_id=community.id) db.session.add(member) db.session.commit() if success is True: - flash('You joined ' + community.title) + if main_user_name: + flash('You joined ' + community.title) + else: + pre_load_message['status'] = 'joined' referrer = request.headers.get('Referer', None) cache.delete_memoized(community_membership, current_user, community) cache.delete_memoized(joined_communities, current_user.id) - if referrer is not None: - return redirect(referrer) + if main_user_name: + if referrer is not None: + return redirect(referrer) + else: + return redirect('/c/' + actor) else: - return redirect('/c/' + actor) + return pre_load_message else: - abort(404) + if main_user_name: + abort(404) + else: + pre_load_message['community'] = actor + pre_load_message['status'] = 'community not found' + return pre_load_message @bp.route('//unsubscribe', methods=['GET']) From cf2400e5d5bff5e4c463a407482495f4df607113 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Thu, 12 Sep 2024 19:01:37 -0400 Subject: [PATCH 04/12] work to make the num of communities user configurable --- app/admin/forms.py | 1 + app/admin/routes.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/admin/forms.py b/app/admin/forms.py index 62ce7c96..33fb5ed3 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -52,6 +52,7 @@ class FederationForm(FlaskForm): submit = SubmitField(_l('Save')) class PreLoadCommunitiesForm(FlaskForm): + communities_num = IntegerField(_l('Number of Communities to add')) pre_load_submit = SubmitField(_l('Add Communities')) class EditCommunityForm(FlaskForm): diff --git a/app/admin/routes.py b/app/admin/routes.py index c75ec433..fcb95c1d 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -201,8 +201,11 @@ def admin_federation(): # this is the pre-load communities button if preload_form.pre_load_submit.data and preload_form.validate(): - # var - how many communities to add, hard-coded to 20 for now, can be made editable later - communities_to_add = 25 + # how many communities to add + if preload_form.communities_num.data: + communities_to_add = preload_form.communities_num.data + else: + communities_to_add = 25 # pull down the community.full.json resp = r.get('https://data.lemmyverse.net/data/community.full.json') @@ -280,16 +283,19 @@ def admin_federation(): for c in community_urls_to_join: # get the relevant url bits server, community = extract_domain_and_actor(c) + # message = {'server': server, 'community': community} # find the community new_community = search_for_community('!' + community + '@' + server) + # message = {'server': server, 'community': community, 'new_community': new_community} # subscribe to the community # since this is using the alt_user_name, capture the messages # returned by do_subscibe as well message = do_subscribe(new_community.ap_id, main_user_name=False) + pre_load_messages.append(message) - flash(_(f'top_20 == {top_20}')) - # flash(_(f'leng_before == {leng_before}, leng_middle == {leng_middle}, leng_after == {leng_after}')) + # flash(_(f'community_urls_to_join == {community_urls_to_join}')) # testing + flash(_(f'Results: {pre_load_messages}')) return redirect(url_for('admin.admin_federation')) # this is the main settings form From cf5bb65a9f5e536d5ea74f74632b9e863d8b4356 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 11:10:10 -0400 Subject: [PATCH 05/12] making do_subscribe a celery task, messages to user updates --- app/admin/forms.py | 4 +++- app/admin/routes.py | 23 +++++++++++++---------- app/community/routes.py | 10 +++++++++- app/templates/admin/federation.html | 5 ++++- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app/admin/forms.py b/app/admin/forms.py index 33fb5ed3..a0d6c009 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -51,10 +51,12 @@ class FederationForm(FlaskForm): blocked_actors = TextAreaField(_l('Discard all posts and comments by users with these words in their name (one per line)')) submit = SubmitField(_l('Save')) + class PreLoadCommunitiesForm(FlaskForm): - communities_num = IntegerField(_l('Number of Communities to add')) + communities_num = IntegerField(_l('Number of Communities to add'), default=25) pre_load_submit = SubmitField(_l('Add Communities')) + class EditCommunityForm(FlaskForm): title = StringField(_l('Title'), validators=[DataRequired()]) url = StringField(_l('Url'), validators=[DataRequired()]) diff --git a/app/admin/routes.py b/app/admin/routes.py index fcb95c1d..c31d50b3 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -283,19 +283,22 @@ def admin_federation(): for c in community_urls_to_join: # get the relevant url bits server, community = extract_domain_and_actor(c) - # message = {'server': server, 'community': community} # find the community new_community = search_for_community('!' + community + '@' + server) - # message = {'server': server, 'community': community, 'new_community': new_community} - # subscribe to the community - # since this is using the alt_user_name, capture the messages - # returned by do_subscibe as well - message = do_subscribe(new_community.ap_id, main_user_name=False) - pre_load_messages.append(message) + # subscribe to the community using alt_profile + # capture the messages returned by do_subscibe + # and show to user if instance is in debug mode + if current_app.debug: + message = do_subscribe(new_community.ap_id, main_user_name=False) + pre_load_messages.append(message) + else: + message_we_wont_do_anything_with = do_subscribe.delay(new_community.ap_id, main_user_name=False) + if current_app.debug: + flash(_(f'Results: {pre_load_messages}')) + else: + flash(_('Subscription process launched to background, check admin/activities for details')) - # flash(_(f'community_urls_to_join == {community_urls_to_join}')) # testing - flash(_(f'Results: {pre_load_messages}')) return redirect(url_for('admin.admin_federation')) # this is the main settings form @@ -334,7 +337,7 @@ def admin_federation(): form.blocked_actors.data = get_setting('actor_blocked_words', '88') return render_template('admin/federation.html', title=_('Federation settings'), - form=form, preload_form=preload_form, + form=form, preload_form=preload_form, current_app_debug=current_app.debug, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()), menu_topics=menu_topics(), diff --git a/app/community/routes.py b/app/community/routes.py index d34dc10c..c9ee7fa4 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -10,7 +10,7 @@ from flask_babel import _ from slugify import slugify from sqlalchemy import or_, desc, text -from app import db, constants, cache +from app import db, constants, cache, celery from app.activitypub.signature import RsaKeys, post_request, default_context, post_request_in_background from app.activitypub.util import notify_about_post, make_image_sizes, resolve_remote_post, extract_domain_and_actor from app.chat.util import send_message @@ -394,6 +394,7 @@ def subscribe(actor): # this is separated out from the route, so it can be used by the # admin.admin_federation.preload_form as well +@celery.task def do_subscribe(actor, main_user_name=True): remote = False actor = actor.strip() @@ -457,6 +458,13 @@ def do_subscribe(actor, main_user_name=True): flash('You joined ' + community.title) else: pre_load_message['status'] = 'joined' + else: + if main_user_name: + # user already subscribed or pending and its not the preload request + pass + else: + pre_load_message['status'] = 'already subscribed, or subsciption pending' + referrer = request.headers.get('Referer', None) cache.delete_memoized(community_membership, current_user, community) cache.delete_memoized(joined_communities, current_user.id) diff --git a/app/templates/admin/federation.html b/app/templates/admin/federation.html index d3cf0f4e..709a9fb3 100644 --- a/app/templates/admin/federation.html +++ b/app/templates/admin/federation.html @@ -17,7 +17,10 @@
-

Use this to "pre-load" the top 50 known threadiverse communities, as rnaked by posts and activity. The list of communities pulls from the same list as LemmyVerse. NSFW communities and communities from banned instances are excluded.

+

Use this to "pre-load" known threadiverse communities, as ranked by posts and activity. The list of communities pulls from the same list as LemmyVerse. NSFW communities and communities from banned instances are excluded.

+ {% if current_app_debug %} +

*** This instance is in development mode. Loading more than 6 communities here could cause timeouts, depending on how your networking is setup. ***

+ {% endif %} {{ render_form(preload_form) }}
From 6b72b9cb64572561a480c992167773c9a739d9c8 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 11:26:00 -0400 Subject: [PATCH 06/12] adding a way to pass a user to do_subscribe --- app/admin/routes.py | 6 ++++-- app/community/routes.py | 34 ++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/admin/routes.py b/app/admin/routes.py index c31d50b3..c5a21fb6 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -279,6 +279,8 @@ def admin_federation(): community_urls_to_join.append(parsed_communities_sorted[i]['url']) # loop through the list and send off the follow requests + # use User #1, the first instance admin + user = User.query.get(1) pre_load_messages = [] for c in community_urls_to_join: # get the relevant url bits @@ -289,10 +291,10 @@ def admin_federation(): # capture the messages returned by do_subscibe # and show to user if instance is in debug mode if current_app.debug: - message = do_subscribe(new_community.ap_id, main_user_name=False) + message = do_subscribe(new_community.ap_id, user, main_user_name=False) pre_load_messages.append(message) else: - message_we_wont_do_anything_with = do_subscribe.delay(new_community.ap_id, main_user_name=False) + message_we_wont_do_anything_with = do_subscribe.delay(new_community.ap_id, user, main_user_name=False) if current_app.debug: flash(_(f'Results: {pre_load_messages}')) diff --git a/app/community/routes.py b/app/community/routes.py index c9ee7fa4..55cd56b8 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -390,12 +390,12 @@ def show_community_rss(actor): @login_required @validation_required def subscribe(actor): - do_subscribe(actor) + do_subscribe(actor, current_user) # this is separated out from the route, so it can be used by the # admin.admin_federation.preload_form as well @celery.task -def do_subscribe(actor, main_user_name=True): +def do_subscribe(actor, user, main_user_name=True): remote = False actor = actor.strip() pre_load_message = {} @@ -407,13 +407,16 @@ def do_subscribe(actor, main_user_name=True): if community is not None: pre_load_message['community'] = community.ap_id - if community.id in communities_banned_from(current_user.id): + # if community.id in communities_banned_from(current_user.id): + if community.id in communities_banned_from(user.id): if main_user_name: abort(401) else: pre_load_message['user_banned'] = True - if community_membership(current_user, community) != SUBSCRIPTION_MEMBER and community_membership(current_user, community) != SUBSCRIPTION_PENDING: - banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first() + # if community_membership(current_user, community) != SUBSCRIPTION_MEMBER and community_membership(current_user, community) != SUBSCRIPTION_PENDING: + if community_membership(user, community) != SUBSCRIPTION_MEMBER and community_membership(user, community) != SUBSCRIPTION_PENDING: + # banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first() + banned = CommunityBan.query.filter_by(user_id=user.id, community_id=community.id).first() if banned: if main_user_name: flash(_('You cannot join this community')) @@ -422,19 +425,23 @@ def do_subscribe(actor, main_user_name=True): success = True if remote: # send ActivityPub message to remote community, asking to follow. Accept message will be sent to our shared inbox - join_request = CommunityJoinRequest(user_id=current_user.id, community_id=community.id) + # join_request = CommunityJoinRequest(user_id=current_user.id, community_id=community.id) + join_request = CommunityJoinRequest(user_id=user.id, community_id=community.id) db.session.add(join_request) db.session.commit() if community.instance.online(): follow = { - "actor": current_user.public_url(main_user_name=main_user_name), + # "actor": current_user.public_url(main_user_name=main_user_name), + "actor": user.public_url(main_user_name=main_user_name), "to": [community.public_url()], "object": community.public_url(), "type": "Follow", "id": f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request.id}" } - success = post_request(community.ap_inbox_url, follow, current_user.private_key, - current_user.public_url() + '#main-key', timeout=10) + # success = post_request(community.ap_inbox_url, follow, current_user.private_key, + # current_user.public_url() + '#main-key', timeout=10) + success = post_request(community.ap_inbox_url, follow, user.private_key, + user.public_url(main_user_name=main_user_name) + '#main-key', timeout=10) if success is False or isinstance(success, str): if 'is not in allowlist' in success: msg_to_user = f'{community.instance.domain} does not allow us to join their communities.' @@ -450,7 +457,8 @@ def do_subscribe(actor, main_user_name=True): pre_load_message['status'] = msg_to_user # for local communities, joining is instant - member = CommunityMember(user_id=current_user.id, community_id=community.id) + # member = CommunityMember(user_id=current_user.id, community_id=community.id) + member = CommunityMember(user_id=user.id, community_id=community.id) db.session.add(member) db.session.commit() if success is True: @@ -466,8 +474,10 @@ def do_subscribe(actor, main_user_name=True): pre_load_message['status'] = 'already subscribed, or subsciption pending' referrer = request.headers.get('Referer', None) - cache.delete_memoized(community_membership, current_user, community) - cache.delete_memoized(joined_communities, current_user.id) + # cache.delete_memoized(community_membership, current_user, community) + # cache.delete_memoized(joined_communities, current_user.id) + cache.delete_memoized(community_membership, user, community) + cache.delete_memoized(joined_communities, user.id) if main_user_name: if referrer is not None: return redirect(referrer) From 859edac084a8d2f2740c64b832f29fad1a3257a3 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 11:34:14 -0400 Subject: [PATCH 07/12] passing user.id rather than the user directly --- app/admin/routes.py | 4 ++-- app/community/routes.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/admin/routes.py b/app/admin/routes.py index c5a21fb6..59e2585e 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -291,10 +291,10 @@ def admin_federation(): # capture the messages returned by do_subscibe # and show to user if instance is in debug mode if current_app.debug: - message = do_subscribe(new_community.ap_id, user, main_user_name=False) + message = do_subscribe(new_community.ap_id, user.id, main_user_name=False) pre_load_messages.append(message) else: - message_we_wont_do_anything_with = do_subscribe.delay(new_community.ap_id, user, main_user_name=False) + message_we_wont_do_anything_with = do_subscribe.delay(new_community.ap_id, user.id, main_user_name=False) if current_app.debug: flash(_(f'Results: {pre_load_messages}')) diff --git a/app/community/routes.py b/app/community/routes.py index 55cd56b8..e560abd9 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -390,14 +390,15 @@ def show_community_rss(actor): @login_required @validation_required def subscribe(actor): - do_subscribe(actor, current_user) + do_subscribe(actor, current_user.id) # this is separated out from the route, so it can be used by the # admin.admin_federation.preload_form as well @celery.task -def do_subscribe(actor, user, main_user_name=True): +def do_subscribe(actor, user_id, main_user_name=True): remote = False actor = actor.strip() + user = User.query.get(user_id) pre_load_message = {} if '@' in actor: community = Community.query.filter_by(banned=False, ap_id=actor).first() From 8eb34ac4d233a35e6a1fa92e81815cefbfbb906f Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 11:44:37 -0400 Subject: [PATCH 08/12] changing referrer check --- app/community/routes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/community/routes.py b/app/community/routes.py index e560abd9..e017d8d8 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -473,8 +473,9 @@ def do_subscribe(actor, user_id, main_user_name=True): pass else: pre_load_message['status'] = 'already subscribed, or subsciption pending' - - referrer = request.headers.get('Referer', None) + + if main_user_name: + referrer = request.headers.get('Referer', None) # cache.delete_memoized(community_membership, current_user, community) # cache.delete_memoized(joined_communities, current_user.id) cache.delete_memoized(community_membership, user, community) From 56b7621fac4bea9401c1045b1d815fdcebdee564 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 12:49:10 -0400 Subject: [PATCH 09/12] adjusting the return for the view --- app/community/routes.py | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/app/community/routes.py b/app/community/routes.py index e017d8d8..d1982156 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -391,6 +391,11 @@ def show_community_rss(actor): @validation_required def subscribe(actor): do_subscribe(actor, current_user.id) + referrer = request.headers.get('Referer', None) + if referrer is not None: + return redirect(referrer) + else: + return redirect('/c/' + actor) # this is separated out from the route, so it can be used by the # admin.admin_federation.preload_form as well @@ -414,9 +419,7 @@ def do_subscribe(actor, user_id, main_user_name=True): abort(401) else: pre_load_message['user_banned'] = True - # if community_membership(current_user, community) != SUBSCRIPTION_MEMBER and community_membership(current_user, community) != SUBSCRIPTION_PENDING: if community_membership(user, community) != SUBSCRIPTION_MEMBER and community_membership(user, community) != SUBSCRIPTION_PENDING: - # banned = CommunityBan.query.filter_by(user_id=current_user.id, community_id=community.id).first() banned = CommunityBan.query.filter_by(user_id=user.id, community_id=community.id).first() if banned: if main_user_name: @@ -426,21 +429,17 @@ def do_subscribe(actor, user_id, main_user_name=True): success = True if remote: # send ActivityPub message to remote community, asking to follow. Accept message will be sent to our shared inbox - # join_request = CommunityJoinRequest(user_id=current_user.id, community_id=community.id) join_request = CommunityJoinRequest(user_id=user.id, community_id=community.id) db.session.add(join_request) db.session.commit() if community.instance.online(): follow = { - # "actor": current_user.public_url(main_user_name=main_user_name), "actor": user.public_url(main_user_name=main_user_name), "to": [community.public_url()], "object": community.public_url(), "type": "Follow", "id": f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request.id}" } - # success = post_request(community.ap_inbox_url, follow, current_user.private_key, - # current_user.public_url() + '#main-key', timeout=10) success = post_request(community.ap_inbox_url, follow, user.private_key, user.public_url(main_user_name=main_user_name) + '#main-key', timeout=10) if success is False or isinstance(success, str): @@ -458,7 +457,6 @@ def do_subscribe(actor, user_id, main_user_name=True): pre_load_message['status'] = msg_to_user # for local communities, joining is instant - # member = CommunityMember(user_id=current_user.id, community_id=community.id) member = CommunityMember(user_id=user.id, community_id=community.id) db.session.add(member) db.session.commit() @@ -468,24 +466,22 @@ def do_subscribe(actor, user_id, main_user_name=True): else: pre_load_message['status'] = 'joined' else: - if main_user_name: + if not main_user_name: # user already subscribed or pending and its not the preload request - pass - else: + # pass + # else: pre_load_message['status'] = 'already subscribed, or subsciption pending' - if main_user_name: - referrer = request.headers.get('Referer', None) - # cache.delete_memoized(community_membership, current_user, community) - # cache.delete_memoized(joined_communities, current_user.id) + # if main_user_name: + # referrer = request.headers.get('Referer', None) cache.delete_memoized(community_membership, user, community) cache.delete_memoized(joined_communities, user.id) - if main_user_name: - if referrer is not None: - return redirect(referrer) - else: - return redirect('/c/' + actor) - else: + if not main_user_name: + # if referrer is not None: + # return redirect(referrer) + # else: + # return redirect('/c/' + actor) + # else: return pre_load_message else: if main_user_name: From 8fca0b7acad26103ef07f9846c96d33a83ca8574 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 13:02:17 -0400 Subject: [PATCH 10/12] comment clean up --- app/community/routes.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/app/community/routes.py b/app/community/routes.py index d1982156..23e98673 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -397,7 +397,7 @@ def subscribe(actor): else: return redirect('/c/' + actor) -# this is separated out from the route, so it can be used by the +# this is separated out from the subscribe route so it can be used by the # admin.admin_federation.preload_form as well @celery.task def do_subscribe(actor, user_id, main_user_name=True): @@ -413,7 +413,6 @@ def do_subscribe(actor, user_id, main_user_name=True): if community is not None: pre_load_message['community'] = community.ap_id - # if community.id in communities_banned_from(current_user.id): if community.id in communities_banned_from(user.id): if main_user_name: abort(401) @@ -467,21 +466,11 @@ def do_subscribe(actor, user_id, main_user_name=True): pre_load_message['status'] = 'joined' else: if not main_user_name: - # user already subscribed or pending and its not the preload request - # pass - # else: pre_load_message['status'] = 'already subscribed, or subsciption pending' - # if main_user_name: - # referrer = request.headers.get('Referer', None) cache.delete_memoized(community_membership, user, community) cache.delete_memoized(joined_communities, user.id) if not main_user_name: - # if referrer is not None: - # return redirect(referrer) - # else: - # return redirect('/c/' + actor) - # else: return pre_load_message else: if main_user_name: From 1e03afe36eedf0e824b2a90ba876e8ff6878fa5b Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 14:04:04 -0400 Subject: [PATCH 11/12] adding a size check on amount of communities requested --- app/admin/routes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/admin/routes.py b/app/admin/routes.py index 59e2585e..833e5f6e 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -275,6 +275,12 @@ def admin_federation(): # get the community urls to join community_urls_to_join = [] + + # if the admin user wants more added than we have, then just add all of them + if communities_to_add > len(parsed_communities_sorted): + communities_to_add = len(parsed_communities_sorted) + + # make the list of urls for i in range(communities_to_add): community_urls_to_join.append(parsed_communities_sorted[i]['url']) From e1d7a117ef1accf20418668194c77b3a817150c0 Mon Sep 17 00:00:00 2001 From: Alan Roberts Date: Fri, 13 Sep 2024 14:08:32 -0400 Subject: [PATCH 12/12] updated user message --- app/admin/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/admin/routes.py b/app/admin/routes.py index 833e5f6e..189ca496 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -305,7 +305,7 @@ def admin_federation(): if current_app.debug: flash(_(f'Results: {pre_load_messages}')) else: - flash(_('Subscription process launched to background, check admin/activities for details')) + flash(_(f'Subscription process for {communities_to_add} of {len(parsed_communities_sorted)} communities launched to background, check admin/activities for details')) return redirect(url_for('admin.admin_federation'))