From 1f0c8eb6ffb4fd0597dc86e6fe356e7ee5fda16c Mon Sep 17 00:00:00 2001 From: rimu <3310831+rimu@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:54:10 +1200 Subject: [PATCH] community blocking #283 --- app/cli.py | 5 ++++- app/community/routes.py | 6 +++++- app/main/routes.py | 8 +++++++- app/post/routes.py | 17 +++++++++++++++-- app/search/routes.py | 6 +++++- app/tag/routes.py | 6 +++++- app/templates/post/post_options.html | 4 +++- app/templates/user/filters.html | 4 ++-- app/topic/routes.py | 5 ++++- app/user/routes.py | 18 +++++++++++++++++- app/utils.py | 8 +++++++- 11 files changed, 74 insertions(+), 13 deletions(-) diff --git a/app/cli.py b/app/cli.py index 1006e6ea..f089c2e3 100644 --- a/app/cli.py +++ b/app/cli.py @@ -25,7 +25,7 @@ from app.models import Settings, BannedInstances, Interest, Role, User, RolePerm utcnow, Site, Instance, File, Notification, Post, CommunityMember, NotificationSubscription, PostReply, Language, \ Tag, InstanceRole from app.utils import file_get_contents, retrieve_block_list, blocked_domains, retrieve_peertube_block_list, \ - shorten_string, get_request, html_to_text + shorten_string, get_request, html_to_text, blocked_communities def register(app): @@ -339,6 +339,9 @@ def register(app): domains_ids = blocked_domains(user.id) if domains_ids: posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None)) + community_ids = blocked_communities(user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) posts = posts.filter(Post.posted_at > user.last_seen).order_by(desc(Post.score)) posts = posts.limit(20).all() diff --git a/app/community/routes.py b/app/community/routes.py index c6b83094..bfefa55c 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -35,7 +35,8 @@ from app.utils import get_setting, render_template, allowlist_html, markdown_to_ request_etag_matches, return_304, instance_banned, can_create_post, can_upvote, can_downvote, user_filters_posts, \ joined_communities, moderating_communities, blocked_domains, mimetype_from_url, blocked_instances, \ community_moderators, communities_banned_from, show_ban_message, recently_upvoted_posts, recently_downvoted_posts, \ - blocked_users, post_ranking, languages_for_form, english_language_id, menu_topics, add_to_modlog + blocked_users, post_ranking, languages_for_form, english_language_id, menu_topics, add_to_modlog, \ + blocked_communities from feedgen.feed import FeedGenerator from datetime import timezone, timedelta from copy import copy @@ -219,6 +220,9 @@ def show_community(community: Community): instance_ids = blocked_instances(current_user.id) if instance_ids: posts = posts.filter(or_(Post.instance_id.not_in(instance_ids), Post.instance_id == None)) + community_ids = blocked_communities(current_user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) # filter blocked users blocked_accounts = blocked_users(current_user.id) diff --git a/app/main/routes.py b/app/main/routes.py index 26c4cd6b..13a0a185 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -26,7 +26,7 @@ from app.utils import render_template, get_setting, gibberish, request_etag_matc joined_communities, moderating_communities, parse_page, theme_list, get_request, markdown_to_html, allowlist_html, \ blocked_instances, communities_banned_from, topic_tree, recently_upvoted_posts, recently_downvoted_posts, \ generate_image_from_video_url, blocked_users, microblog_content_to_title, menu_topics, languages_for_form, \ - make_cache_key + make_cache_key, blocked_communities from app.models import Community, CommunityMember, Post, Site, User, utcnow, Domain, Topic, File, Instance, \ InstanceRole, Notification, Language, community_language, PostReply, ModLog @@ -119,6 +119,9 @@ def home_page(type, sort): instance_ids = blocked_instances(current_user.id) if instance_ids: posts = posts.filter(or_(Post.instance_id.not_in(instance_ids), Post.instance_id == None)) + community_ids = blocked_communities(current_user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) # filter blocked users blocked_accounts = blocked_users(current_user.id) if blocked_accounts: @@ -153,6 +156,9 @@ def home_page(type, sort): banned_from = communities_banned_from(current_user.id) if banned_from: active_communities = active_communities.filter(Community.id.not_in(banned_from)) + community_ids = blocked_communities(current_user.id) + if community_ids: + active_communities = active_communities.filter(Community.id.not_in(community_ids)) active_communities = active_communities.order_by(desc(Community.last_active)).limit(5).all() # Voting history diff --git a/app/post/routes.py b/app/post/routes.py index 7aeea859..53de77f1 100644 --- a/app/post/routes.py +++ b/app/post/routes.py @@ -23,7 +23,7 @@ from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, SUBSCRIPTION_ from app.models import Post, PostReply, \ PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, \ Topic, User, Instance, NotificationSubscription, UserFollower, Poll, PollChoice, PollChoiceVote, PostBookmark, \ - PostReplyBookmark + PostReplyBookmark, CommunityBlock from app.post import bp from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \ shorten_string, markdown_to_text, gibberish, ap_datetime, return_304, \ @@ -31,7 +31,7 @@ from app.utils import get_setting, render_template, allowlist_html, markdown_to_ reply_already_exists, reply_is_just_link_to_gif_reaction, confidence, moderating_communities, joined_communities, \ blocked_instances, blocked_domains, community_moderators, blocked_phrases, show_ban_message, recently_upvoted_posts, \ recently_downvoted_posts, recently_upvoted_post_replies, recently_downvoted_post_replies, reply_is_stupid, \ - languages_for_form, menu_topics, add_to_modlog + languages_for_form, menu_topics, add_to_modlog, blocked_communities def show_post(post_id: int): @@ -1464,6 +1464,19 @@ def post_block_domain(post_id: int): return redirect(post.community.local_url()) +@bp.route('/post//block_community', methods=['GET', 'POST']) +@login_required +def post_block_community(post_id: int): + post = Post.query.get_or_404(post_id) + existing = CommunityBlock.query.filter_by(user_id=current_user.id, community_id=post.community_id).first() + if not existing: + db.session.add(CommunityBlock(user_id=current_user.id, community_id=post.community_id)) + db.session.commit() + cache.delete_memoized(blocked_communities, current_user.id) + flash(_('Posts in %(name)s will be hidden.', name=post.community.display_name())) + return redirect(post.community.local_url()) + + @bp.route('/post//block_instance', methods=['GET', 'POST']) @login_required def post_block_instance(post_id: int): diff --git a/app/search/routes.py b/app/search/routes.py index 7010f37e..660a47b8 100644 --- a/app/search/routes.py +++ b/app/search/routes.py @@ -6,7 +6,8 @@ from sqlalchemy import or_ from app.models import Post, Language, Community from app.search import bp from app.utils import moderating_communities, joined_communities, render_template, blocked_domains, blocked_instances, \ - communities_banned_from, recently_upvoted_posts, recently_downvoted_posts, blocked_users, menu_topics + communities_banned_from, recently_upvoted_posts, recently_downvoted_posts, blocked_users, menu_topics, \ + blocked_communities from app.community.forms import RetrieveRemotePost from app.activitypub.util import resolve_remote_post_from_search @@ -42,6 +43,9 @@ def run_search(): instance_ids = blocked_instances(current_user.id) if instance_ids: posts = posts.filter(or_(Post.instance_id.not_in(instance_ids), Post.instance_id == None)) + community_ids = blocked_communities(current_user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) # filter blocked users blocked_accounts = blocked_users(current_user.id) if blocked_accounts: diff --git a/app/tag/routes.py b/app/tag/routes.py index c3b1a57e..dcd10c3b 100644 --- a/app/tag/routes.py +++ b/app/tag/routes.py @@ -11,7 +11,8 @@ from app.inoculation import inoculation from app.models import Post, Community, Tag, post_tag from app.tag import bp from app.utils import render_template, permission_required, joined_communities, moderating_communities, \ - user_filters_posts, blocked_instances, blocked_users, blocked_domains, menu_topics, mimetype_from_url + user_filters_posts, blocked_instances, blocked_users, blocked_domains, menu_topics, mimetype_from_url, \ + blocked_communities from sqlalchemy import desc, or_ @@ -36,6 +37,9 @@ def show_tag(tag): instance_ids = blocked_instances(current_user.id) if instance_ids: posts = posts.filter(or_(Post.instance_id.not_in(instance_ids), Post.instance_id == None)) + community_ids = blocked_communities(current_user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) # filter blocked users blocked_accounts = blocked_users(current_user.id) if blocked_accounts: diff --git a/app/templates/post/post_options.html b/app/templates/post/post_options.html index 36c7e048..7ce8cdbb 100644 --- a/app/templates/post/post_options.html +++ b/app/templates/post/post_options.html @@ -40,9 +40,11 @@ {% if post.user_id != current_user.id -%}
  • {{ _('Block post author @%(author_name)s', author_name=post.author.user_name) }}
  • +
  • + {{ _('Block community %(community_name)s', community_name=post.community.display_name()) }}
  • {% if post.community.is_moderator() or current_user.is_admin() -%}
  • - {{ _('Ban post author @%(author_name)s from
    %(community_name)s', author_name=post.author.user_name, community_name=post.community.title) }}
  • + {{ _('Ban post author @%(author_name)s from %(community_name)s', author_name=post.author.user_name, community_name=post.community.title) }} {% endif -%} {% if post.domain_id -%}
  • diff --git a/app/templates/user/filters.html b/app/templates/user/filters.html index 2c4fc756..ce9381dd 100644 --- a/app/templates/user/filters.html +++ b/app/templates/user/filters.html @@ -106,7 +106,7 @@ {% for community in blocked_communities %} {{ community.title }} - {{ _('Unblock') }} + {{ _('Unblock') }} {% endfor %} @@ -141,7 +141,7 @@ {% for instance in blocked_instances %} - {{ instance.domain }} + {{ instance.domain }} {{ _('Unblock') }} {% endfor %} diff --git a/app/topic/routes.py b/app/topic/routes.py index 7017ba83..17ec86fc 100644 --- a/app/topic/routes.py +++ b/app/topic/routes.py @@ -21,7 +21,7 @@ from app import db, celery, cache from app.topic.forms import ChooseTopicsForm, SuggestTopicsForm from app.utils import render_template, user_filters_posts, moderating_communities, joined_communities, \ community_membership, blocked_domains, validation_required, mimetype_from_url, blocked_instances, \ - communities_banned_from, blocked_users, menu_topics + communities_banned_from, blocked_users, menu_topics, blocked_communities @bp.route('/topic/', methods=['GET']) @@ -75,6 +75,9 @@ def show_topic(topic_path): instance_ids = blocked_instances(current_user.id) if instance_ids: posts = posts.filter(or_(Post.instance_id.not_in(instance_ids), Post.instance_id == None)) + community_ids = blocked_communities(current_user.id) + if community_ids: + posts = posts.filter(Post.community_id.not_in(community_ids)) # filter blocked users blocked_accounts = blocked_users(current_user.id) if blocked_accounts: diff --git a/app/user/routes.py b/app/user/routes.py index 9bbd1566..fb800ee1 100644 --- a/app/user/routes.py +++ b/app/user/routes.py @@ -23,7 +23,8 @@ from app.user.utils import purge_user_then_delete, unsubscribe_from_community from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string, \ is_image_url, ensure_directory_exists, gibberish, file_get_contents, community_membership, user_filters_home, \ user_filters_posts, user_filters_replies, moderating_communities, joined_communities, theme_list, blocked_instances, \ - allowlist_html, recently_upvoted_posts, recently_downvoted_posts, blocked_users, menu_topics, add_to_modlog + allowlist_html, recently_upvoted_posts, recently_downvoted_posts, blocked_users, menu_topics, add_to_modlog, \ + blocked_communities from sqlalchemy import desc, or_, text import os @@ -509,6 +510,21 @@ def instance_unblock(instance_id): return redirect(goto) +@bp.route('/user/community//unblock', methods=['GET']) +@login_required +def user_community_unblock(community_id): + community = Community.query.get_or_404(community_id) + existing_block = CommunityBlock.query.filter_by(user_id=current_user.id, community_id=community.id).first() + if existing_block: + db.session.delete(existing_block) + db.session.commit() + cache.delete_memoized(blocked_communities, current_user.id) + flash(f'{community.display_name()} has been unblocked.') + + goto = request.args.get('redirect') if 'redirect' in request.args else url_for('user.user_settings_filters') + return redirect(goto) + + @bp.route('/delete_account', methods=['GET', 'POST']) @login_required def delete_account(): diff --git a/app/utils.py b/app/utils.py index 8f9e15dd..c85a98b1 100644 --- a/app/utils.py +++ b/app/utils.py @@ -36,7 +36,7 @@ from PIL import Image, ImageOps from app.models import Settings, Domain, Instance, BannedInstances, User, Community, DomainBlock, ActivityPubLog, IpBan, \ Site, Post, PostReply, utcnow, Filter, CommunityMember, InstanceBlock, CommunityBan, Topic, UserBlock, Language, \ - File, ModLog + File, ModLog, CommunityBlock # Flask's render_template function, with support for themes added @@ -436,6 +436,12 @@ def blocked_domains(user_id) -> List[int]: return [block.domain_id for block in blocks] +@cache.memoize(timeout=86400) +def blocked_communities(user_id) -> List[int]: + blocks = CommunityBlock.query.filter_by(user_id=user_id) + return [block.community_id for block in blocks] + + @cache.memoize(timeout=86400) def blocked_instances(user_id) -> List[int]: blocks = InstanceBlock.query.filter_by(user_id=user_id)