mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
53260c25dd
21 changed files with 219 additions and 49 deletions
|
@ -339,10 +339,19 @@ def refresh_user_profile_task(user_id):
|
|||
if actor_data.status_code == 200:
|
||||
activity_json = actor_data.json()
|
||||
actor_data.close()
|
||||
|
||||
# update indexible state on their posts, if necessary
|
||||
new_indexable = activity_json['indexable'] if 'indexable' in activity_json else True
|
||||
if new_indexable != user.indexable:
|
||||
db.session.execute(text('UPDATE "post" set indexable = :indexable WHERE user_id = :user_id'),
|
||||
{'user_id': user.id,
|
||||
'indexable': new_indexable})
|
||||
|
||||
user.user_name = activity_json['preferredUsername']
|
||||
user.about_html = parse_summary(activity_json)
|
||||
user.ap_fetched_at = utcnow()
|
||||
user.public_key=activity_json['publicKey']['publicKeyPem']
|
||||
user.public_key = activity_json['publicKey']['publicKeyPem']
|
||||
user.indexable = new_indexable
|
||||
|
||||
avatar_changed = cover_changed = False
|
||||
if 'icon' in activity_json:
|
||||
|
@ -594,6 +603,7 @@ def post_json_to_model(post_json, user, community) -> Post:
|
|||
last_active=post_json['published'],
|
||||
instance_id=user.instance_id
|
||||
)
|
||||
post.indexable = user.indexable
|
||||
if 'source' in post_json and \
|
||||
post_json['source']['mediaType'] == 'text/markdown':
|
||||
post.body = post_json['source']['content']
|
||||
|
@ -1212,7 +1222,8 @@ def create_post(activity_log: ActivityPubLog, community: Community, request_json
|
|||
type=constants.POST_TYPE_ARTICLE,
|
||||
up_votes=1,
|
||||
score=instance_weight(user.ap_domain),
|
||||
instance_id=user.instance_id
|
||||
instance_id=user.instance_id,
|
||||
indexable=user.indexable
|
||||
)
|
||||
# Get post content. Lemmy and Kbin put this in different places.
|
||||
if 'source' in request_json['object'] and isinstance(request_json['object']['source'], dict) and request_json['object']['source']['mediaType'] == 'text/markdown': # Lemmy
|
||||
|
@ -1227,7 +1238,10 @@ def create_post(activity_log: ActivityPubLog, community: Community, request_json
|
|||
post.url = request_json['object']['attachment'][0]['href']
|
||||
if is_image_url(post.url):
|
||||
post.type = POST_TYPE_IMAGE
|
||||
image = File(source_url=request_json['object']['image']['url'])
|
||||
if 'image' in request_json['object'] and 'url' in request_json['object']['image']:
|
||||
image = File(source_url=request_json['object']['image']['url'])
|
||||
else:
|
||||
image = File(source_url=post.url)
|
||||
db.session.add(image)
|
||||
post.image = image
|
||||
else:
|
||||
|
|
|
@ -127,6 +127,14 @@ class ReportCommunityForm(FlaskForm):
|
|||
report_remote = BooleanField('Also send report to originating instance')
|
||||
submit = SubmitField(_l('Report'))
|
||||
|
||||
def reasons_to_string(self, reason_data) -> str:
|
||||
result = []
|
||||
for reason_id in reason_data:
|
||||
for choice in self.reason_choices:
|
||||
if choice[0] == reason_id:
|
||||
result.append(str(choice[1]))
|
||||
return ', '.join(result)
|
||||
|
||||
|
||||
class DeleteCommunityForm(FlaskForm):
|
||||
submit = SubmitField(_l('Delete community'))
|
||||
|
|
|
@ -23,7 +23,7 @@ from app.community import bp
|
|||
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
||||
shorten_string, gibberish, community_membership, ap_datetime, \
|
||||
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
|
||||
joined_communities, moderating_communities, blocked_domains, mimetype_from_url, blocked_instances
|
||||
from feedgen.feed import FeedGenerator
|
||||
from datetime import timezone, timedelta
|
||||
|
||||
|
@ -152,9 +152,13 @@ def show_community(community: Community):
|
|||
posts = posts.filter(Post.nsfw == False)
|
||||
content_filters = user_filters_posts(current_user.id)
|
||||
|
||||
# filter domains and instances
|
||||
domains_ids = blocked_domains(current_user.id)
|
||||
if domains_ids:
|
||||
posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None))
|
||||
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))
|
||||
|
||||
if sort == '' or sort == 'hot':
|
||||
posts = posts.order_by(desc(Post.ranking)).order_by(desc(Post.posted_at))
|
||||
|
|
|
@ -164,6 +164,7 @@ def url_to_thumbnail_file(filename) -> File:
|
|||
|
||||
|
||||
def save_post(form, post: Post):
|
||||
post.indexable = current_user.indexable
|
||||
post.nsfw = form.nsfw.data
|
||||
post.nsfl = form.nsfl.data
|
||||
post.notify_author = form.notify_author.data
|
||||
|
|
|
@ -8,9 +8,9 @@ from app import db, constants, cache
|
|||
from app.inoculation import inoculation
|
||||
from app.models import Post, Domain, Community, DomainBlock
|
||||
from app.domain import bp
|
||||
from app.utils import get_setting, render_template, permission_required, joined_communities, moderating_communities, \
|
||||
user_filters_posts, blocked_domains
|
||||
from sqlalchemy import desc
|
||||
from app.utils import render_template, permission_required, joined_communities, moderating_communities, \
|
||||
user_filters_posts, blocked_domains, blocked_instances
|
||||
from sqlalchemy import desc, or_
|
||||
|
||||
|
||||
@bp.route('/d/<domain_id>', methods=['GET'])
|
||||
|
@ -31,6 +31,10 @@ def show_domain(domain_id):
|
|||
else:
|
||||
posts = Post.query.join(Community).filter(Post.domain_id == domain.id, Community.banned == False).order_by(desc(Post.posted_at))
|
||||
|
||||
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))
|
||||
|
||||
if current_user.is_authenticated:
|
||||
content_filters = user_filters_posts(current_user.id)
|
||||
else:
|
||||
|
@ -77,7 +81,7 @@ def domains():
|
|||
|
||||
@bp.route('/domains/banned', methods=['GET'])
|
||||
@login_required
|
||||
def blocked_domains():
|
||||
def domains_blocked_list():
|
||||
if not current_user.trustworthy():
|
||||
abort(404)
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ from sqlalchemy import select, desc, text
|
|||
from sqlalchemy_searchable import search
|
||||
from app.utils import render_template, get_setting, gibberish, request_etag_matches, return_304, blocked_domains, \
|
||||
ap_datetime, ip_address, retrieve_block_list, shorten_string, markdown_to_text, user_filters_home, \
|
||||
joined_communities, moderating_communities, parse_page, theme_list, get_request, markdown_to_html, allowlist_html
|
||||
joined_communities, moderating_communities, parse_page, theme_list, get_request, markdown_to_html, allowlist_html, \
|
||||
blocked_instances
|
||||
from app.models import Community, CommunityMember, Post, Site, User, utcnow, Domain, Topic, File, Instance, \
|
||||
InstanceRole, Notification
|
||||
from PIL import Image
|
||||
|
@ -103,6 +104,9 @@ def home_page(type, sort):
|
|||
domains_ids = blocked_domains(current_user.id)
|
||||
if domains_ids:
|
||||
posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None))
|
||||
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))
|
||||
content_filters = user_filters_home(current_user.id)
|
||||
|
||||
# Sorting
|
||||
|
|
|
@ -776,7 +776,7 @@ class Post(db.Model):
|
|||
nsfl = db.Column(db.Boolean, default=False, index=True)
|
||||
sticky = db.Column(db.Boolean, default=False)
|
||||
notify_author = db.Column(db.Boolean, default=True)
|
||||
indexable = db.Column(db.Boolean, default=False)
|
||||
indexable = db.Column(db.Boolean, default=True)
|
||||
from_bot = db.Column(db.Boolean, default=False, index=True)
|
||||
created_at = db.Column(db.DateTime, index=True, default=utcnow) # this is when the content arrived here
|
||||
posted_at = db.Column(db.DateTime, index=True, default=utcnow) # this is when the original server created it
|
||||
|
|
|
@ -7,7 +7,7 @@ from flask_login import login_user, logout_user, current_user, login_required
|
|||
from flask_babel import _
|
||||
from sqlalchemy import or_, desc
|
||||
|
||||
from app import db, constants
|
||||
from app import db, constants, cache
|
||||
from app.activitypub.signature import HttpSignature, post_request
|
||||
from app.activitypub.util import default_context
|
||||
from app.community.util import save_post, send_to_remote_instance
|
||||
|
@ -22,7 +22,8 @@ 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, \
|
||||
request_etag_matches, ip_address, user_ip_banned, instance_banned, can_downvote, can_upvote, post_ranking, \
|
||||
reply_already_exists, reply_is_just_link_to_gif_reaction, confidence, moderating_communities, joined_communities
|
||||
reply_already_exists, reply_is_just_link_to_gif_reaction, confidence, moderating_communities, joined_communities, \
|
||||
blocked_instances, blocked_domains
|
||||
|
||||
|
||||
def show_post(post_id: int):
|
||||
|
@ -215,6 +216,7 @@ def show_post(post_id: int):
|
|||
canonical=post.ap_id, form=form, replies=replies, THREAD_CUTOFF_DEPTH=constants.THREAD_CUTOFF_DEPTH,
|
||||
description=description, og_image=og_image, POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE,
|
||||
POST_TYPE_LINK=constants.POST_TYPE_LINK, POST_TYPE_ARTICLE=constants.POST_TYPE_ARTICLE,
|
||||
noindex=not post.author.indexable,
|
||||
etag=f"{post.id}{sort}_{hash(post.last_active)}", markdown_editor=current_user.is_authenticated and current_user.markdown_editor,
|
||||
low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER,
|
||||
moderating_communities=moderating_communities(current_user.get_id()),
|
||||
|
@ -602,6 +604,7 @@ def post_reply_options(post_id: int, comment_id: int):
|
|||
def post_edit(post_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
form = CreatePostForm()
|
||||
del form.communities
|
||||
if post.user_id == current_user.id or post.community.is_moderator():
|
||||
if g.site.enable_nsfl is False:
|
||||
form.nsfl.render_kw = {'disabled': True}
|
||||
|
@ -612,7 +615,7 @@ def post_edit(post_id: int):
|
|||
form.nsfl.data = True
|
||||
form.nsfw.render_kw = {'disabled': True}
|
||||
|
||||
form.communities.choices = [(c.id, c.display_name()) for c in current_user.communities()]
|
||||
#form.communities.choices = [(c.id, c.display_name()) for c in current_user.communities()]
|
||||
|
||||
if form.validate_on_submit():
|
||||
save_post(form, post)
|
||||
|
@ -848,6 +851,7 @@ def post_block_domain(post_id: int):
|
|||
if not existing:
|
||||
db.session.add(DomainBlock(user_id=current_user.id, domain_id=post.domain_id))
|
||||
db.session.commit()
|
||||
cache.delete_memoized(blocked_domains, current_user.id)
|
||||
flash(_('Posts linking to %(name)s will be hidden.', name=post.domain.name))
|
||||
return redirect(post.community.local_url())
|
||||
|
||||
|
@ -860,6 +864,7 @@ def post_block_instance(post_id: int):
|
|||
if not existing:
|
||||
db.session.add(InstanceBlock(user_id=current_user.id, instance_id=post.instance_id))
|
||||
db.session.commit()
|
||||
cache.delete_memoized(blocked_instances, current_user.id)
|
||||
flash(_('Content from %(name)s will be hidden.', name=post.instance.domain))
|
||||
return redirect(post.community.local_url())
|
||||
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
from typing import List
|
||||
|
||||
from sqlalchemy import desc, text
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import desc, text, or_
|
||||
|
||||
from app import db
|
||||
from app.models import PostReply
|
||||
from app.utils import blocked_instances
|
||||
|
||||
|
||||
# replies to a post, in a tree, sorted by a variety of methods
|
||||
def post_replies(post_id: int, sort_by: str, show_first: int = 0) -> List[PostReply]:
|
||||
comments = PostReply.query.filter_by(post_id=post_id)
|
||||
if current_user.is_authenticated:
|
||||
instance_ids = blocked_instances(current_user.id)
|
||||
if instance_ids:
|
||||
comments = comments.filter(or_(PostReply.instance_id.not_in(instance_ids), PostReply.instance_id == None))
|
||||
if sort_by == 'hot':
|
||||
comments = comments.order_by(desc(PostReply.ranking))
|
||||
elif sort_by == 'top':
|
||||
|
@ -36,6 +42,10 @@ def get_comment_branch(post_id: int, comment_id: int, sort_by: str) -> List[Post
|
|||
return []
|
||||
|
||||
comments = PostReply.query.filter(PostReply.post_id == post_id)
|
||||
if current_user.is_authenticated:
|
||||
instance_ids = blocked_instances(current_user.id)
|
||||
if instance_ids:
|
||||
comments = comments.filter(or_(PostReply.instance_id.not_in(instance_ids), PostReply.instance_id == None))
|
||||
if sort_by == 'hot':
|
||||
comments = comments.order_by(desc(PostReply.ranking))
|
||||
elif sort_by == 'top':
|
||||
|
|
|
@ -5,11 +5,10 @@ from sqlalchemy import or_
|
|||
|
||||
from app.models import Post
|
||||
from app.search import bp
|
||||
from app.utils import moderating_communities, joined_communities, render_template, blocked_domains
|
||||
from app.utils import moderating_communities, joined_communities, render_template, blocked_domains, blocked_instances
|
||||
|
||||
|
||||
@bp.route('/search', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def run_search():
|
||||
if request.args.get('q') is not None:
|
||||
q = request.args.get('q')
|
||||
|
@ -17,16 +16,26 @@ def run_search():
|
|||
low_bandwidth = request.cookies.get('low_bandwidth', '0') == '1'
|
||||
|
||||
posts = Post.query.search(q)
|
||||
if current_user.ignore_bots:
|
||||
if current_user.is_authenticated:
|
||||
if current_user.ignore_bots:
|
||||
posts = posts.filter(Post.from_bot == False)
|
||||
if current_user.show_nsfl is False:
|
||||
posts = posts.filter(Post.nsfl == False)
|
||||
if current_user.show_nsfw is False:
|
||||
posts = posts.filter(Post.nsfw == False)
|
||||
domains_ids = blocked_domains(current_user.id)
|
||||
if domains_ids:
|
||||
posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None))
|
||||
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))
|
||||
else:
|
||||
posts = posts.filter(Post.from_bot == False)
|
||||
if current_user.show_nsfl is False:
|
||||
posts = posts.filter(Post.nsfl == False)
|
||||
if current_user.show_nsfw is False:
|
||||
posts = posts.filter(Post.nsfw == False)
|
||||
|
||||
domains_ids = blocked_domains(current_user.id)
|
||||
if domains_ids:
|
||||
posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None))
|
||||
posts = posts.filter(Post.indexable == True)
|
||||
|
||||
posts = posts.paginate(page=page, per_page=100 if current_user.is_authenticated and not low_bandwidth else 50,
|
||||
error_out=False)
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
{% if rss_feed %}
|
||||
<link rel="alternate" type="application/rss+xml" title="{{ rss_feed_name }}" href="{{ rss_feed }}" />
|
||||
{% endif %}
|
||||
{% if noindex %}
|
||||
<meta name="robots" content="noindex">
|
||||
{% endif %}
|
||||
<script nonce="{{ session['nonce']}}">
|
||||
const getStoredTheme = () => localStorage.getItem('theme')
|
||||
const setStoredTheme = theme => localStorage.setItem('theme', theme)
|
||||
|
|
|
@ -35,20 +35,12 @@
|
|||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th><span title="{{ _('How many times has something on this domain been posted?') }}"># Posts</span></th>
|
||||
{% if not current_user.is_anonymous %}{% if user_access('ban users', current_user.id) or user_access('manage users', current_user.id) %}<th>Actions</th>{%endif%}{%endif%}
|
||||
<th><span title="{{ _('How many times has something on this domain been posted') }}"># Posts</span></th>
|
||||
</tr>
|
||||
{% for domain in domains %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('domain.show_domain', domain_id=domain.id) }}">{{ domain.name }}</a></td>
|
||||
<td>{{ domain.post_count }}</td>
|
||||
{% if not current_user.is_anonymous %}
|
||||
{% if user_access('ban users', current_user.id) or user_access('manage users', current_user.id) %}
|
||||
<td>
|
||||
<a class="confirm_first btn btn-primary" title="{{ _('Banning this domain will delete all posts linking to this domain and prevent future posts linking to that domain.') }}" href="/d/{{ domain.id }}/ban">{{ _('Ban') }}</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
{% if user_access('ban users', current_user.id) or user_access('manage users', current_user.id) %}<th>Actions</th>{%endif%}
|
||||
{% if user_access('ban users', current_user.id) or user_access('manage users', current_user.id) %}<th>Actions</th>{% endif %}
|
||||
</tr>
|
||||
{% for domain in domains %}
|
||||
<tr>
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
{% macro render_comment(comment) %}
|
||||
<div id="comment_{{ comment['comment'].id }}" class="comment {% if comment['comment'].score <= -10 %}low_score{% endif %}
|
||||
{% if comment['comment'].author.id == post.author.id %}original_poster{% endif %}" aria-level="{{ comment['comment'].depth + 1 }}" role="treeitem" aria-expanded="true" tabindex="0">
|
||||
<div class="limit_height">
|
||||
<div class="limit_height">{% if not comment['comment'].author.indexable %}<!--googleoff: all-->{% endif %}
|
||||
<div class="comment_author">
|
||||
{% if comment['comment'].author.deleted %}
|
||||
[deleted]
|
||||
|
@ -107,7 +107,7 @@
|
|||
</div>
|
||||
<div class="comment_body hidable {% if comment['comment'].reports and current_user.is_authenticated and post.community.is_moderator(current_user) %}reported{% endif %}">
|
||||
{{ comment['comment'].body_html | safe }}
|
||||
</div>
|
||||
</div>{% if not comment['comment'].author.indexable %}<!--googleon: all-->{% endif %}
|
||||
</div>
|
||||
<div class="comment_actions hidable">
|
||||
{% if post.comments_enabled %}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
<h1>{{ _('Edit post') }}</h1>
|
||||
<form method="post" enctype="multipart/form-data" role="form">
|
||||
{{ form.csrf_token() }}
|
||||
{{ render_field(form.communities) }}
|
||||
<nav id="post_type_chooser">
|
||||
<div class="nav nav-tabs nav-justified" id="typeTab" role="tablist">
|
||||
<button class="nav-link active" id="discussion-tab" data-bs-toggle="tab" data-bs-target="#discussion-tab-pane"
|
||||
|
@ -143,11 +142,20 @@
|
|||
<h2>{{ post.community.title }}</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{ post.community.description|safe }}</p>
|
||||
<p>{{ post.community.rules|safe }}</p>
|
||||
<p>{{ post.community.description_html|safe if post.community.description_html else '' }}</p>
|
||||
<p>{{ post.community.rules_html|safe if post.community.rules_html else '' }}</p>
|
||||
{% if len(mods) > 0 and not post.community.private_mods %}
|
||||
<h3>Moderators</h3>
|
||||
<ul class="moderator_list">
|
||||
{% for mod in mods %}
|
||||
<li><a href="/u/{{ mod.link() }}">{{ mod.display_name() }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include "_inoculation_links.html" %}
|
||||
</aside>
|
||||
{% include "_inoculation_links.html" %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -50,10 +50,92 @@
|
|||
{% endif %}
|
||||
<h5>Blocks</h5>
|
||||
<p class="card-text">Manage what users, communities, domains or instances you want to block. Blocking them means you will no longer see any posts associated with them.</p>
|
||||
<a class="btn btn-primary" href="">Manage User Blocks</a>
|
||||
<a class="btn btn-primary" href="">Manage Communities Blocks</a>
|
||||
<a class="btn btn-primary" href="">Manage Domain Blocks</a>
|
||||
<a class="btn btn-primary" href="">Manage Instance Blocks</a>
|
||||
<nav id="block_chooser">
|
||||
<div class="nav nav-tabs nav-justified" id="typeTab" role="tablist">
|
||||
<button class="nav-link active" id="discussion-tab" data-bs-toggle="tab" data-bs-target="#people-tab-pane"
|
||||
type="button" role="tab" aria-controls="discussion-tab-pane" aria-selected="true">{{ _('People') }}</button>
|
||||
<button class="nav-link" id="link-tab" data-bs-toggle="tab" data-bs-target="#communities-tab-pane"
|
||||
type="button" role="tab" aria-controls="link-tab-pane" aria-selected="false">{{ _('Communities') }}</button>
|
||||
<button class="nav-link" id="image-tab" data-bs-toggle="tab" data-bs-target="#domains-tab-pane"
|
||||
type="button" role="tab" aria-controls="image-tab-pane" aria-selected="false">{{ _('Domains') }}</button>
|
||||
<button class="nav-link" id="poll-tab" data-bs-toggle="tab" data-bs-target="#instances-tab-pane"
|
||||
type="button" role="tab" aria-controls="poll-tab-pane" aria-selected="false">{{ _('Instances') }}</button>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="people-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
||||
{% if blocked_users %}
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th>{{ _('Unblock') }}</th>
|
||||
</tr>
|
||||
{% for user in blocked_users %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('activitypub.user_profile', actor=user.ap_id if user.ap_id is not none else user.user_name) }}">{{ user.display_name() }}</a></td>
|
||||
<td><a class="no-underline confirm_first" href="{{ url_for('user.unblock_profile', actor=user.link()) }}" rel="nofollow"><span class="fe fe-delete"> {{ _('Unblock') }}</span></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>{{ _('No blocked people') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="communities-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
||||
{% if blocked_communities %}
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th>{{ _('Unblock') }}</th>
|
||||
</tr>
|
||||
{% for community in blocked_communities %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not none else community.name) }}">{{ community.title }}</a></td>
|
||||
<td><a class="no-underline confirm_first" href="#" rel="nofollow"><span class="fe fe-delete"> {{ _('Unblock') }}</span></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>{{ _('No blocked communities') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="domains-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
||||
{% if blocked_domains %}
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th>{{ _('Unblock') }}</th>
|
||||
</tr>
|
||||
{% for domain in blocked_domains %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('domain.show_domain', domain_id=domain.id) }}">{{ domain.name }}</a></td>
|
||||
<td><a class="no-underline confirm_first" href="{{ url_for('domain.domain_unblock', domain_id=domain.id) }}" rel="nofollow"><span class="fe fe-delete"> {{ _('Unblock') }}</span></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>{{ _('No blocked domains') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="instances-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
||||
{% if blocked_instances %}
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<th>{{ _('Unblock') }}</th>
|
||||
</tr>
|
||||
{% for instance in blocked_instances %}
|
||||
<tr>
|
||||
<td><a href="#">{{ instance.domain }}</a></td>
|
||||
<td><a class="no-underline confirm_first" href="#" rel="nofollow"><span class="fe fe-delete"> {{ _('Unblock') }}</span></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>{{ _('No blocked instances') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -49,11 +49,11 @@
|
|||
<a class="btn btn-primary" href="https://matrix.to/#/{{ user.matrix_user_id }}" rel="nofollow" aria-label="{{ _('Send message with matrix chat') }}">{{ _('Send message using Matrix') }}</a>
|
||||
{% endif %}
|
||||
{% if current_user.has_blocked_user(user.id) %}
|
||||
<a class="btn btn-primary" href="{{ url_for('user.unblock_profile', actor=user.link()) }}" rel="nofollow">{{ _('Unblock user') }}</a>
|
||||
<a class="btn btn-primary" href="{{ url_for('user.unblock_profile', actor=user.link()) }}" rel="nofollow">{{ _('Unblock') }}</a>
|
||||
{% else %}
|
||||
<a class="btn btn-primary confirm_first" href="{{ url_for('user.block_profile', actor=user.link()) }}" rel="nofollow">{{ _('Block user') }}</a>
|
||||
<a class="btn btn-primary confirm_first" href="{{ url_for('user.block_profile', actor=user.link()) }}" rel="nofollow">{{ _('Block') }}</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-primary" href="{{ url_for('user.report_profile', actor=user.link()) }}" rel="nofollow">{{ _('Report user') }}</a>
|
||||
<a class="btn btn-primary" href="{{ url_for('user.report_profile', actor=user.link()) }}" rel="nofollow">{{ _('Report') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="small">{{ _('Joined') }}: {{ moment(user.created).fromNow(refresh=True) }}<br />
|
||||
|
|
|
@ -16,7 +16,7 @@ from app.topic import bp
|
|||
from app import db, celery, cache
|
||||
from app.topic.forms import ChooseTopicsForm
|
||||
from app.utils import render_template, user_filters_posts, moderating_communities, joined_communities, \
|
||||
community_membership, blocked_domains, validation_required, mimetype_from_url
|
||||
community_membership, blocked_domains, validation_required, mimetype_from_url, blocked_instances
|
||||
|
||||
|
||||
@bp.route('/topic/<path:topic_path>', methods=['GET'])
|
||||
|
@ -65,6 +65,9 @@ def show_topic(topic_path):
|
|||
domains_ids = blocked_domains(current_user.id)
|
||||
if domains_ids:
|
||||
posts = posts.filter(or_(Post.domain_id.not_in(domains_ids), Post.domain_id == None))
|
||||
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))
|
||||
|
||||
# sorting
|
||||
if sort == '' or sort == 'hot':
|
||||
|
|
|
@ -38,7 +38,7 @@ class SettingsForm(FlaskForm):
|
|||
nsfl = BooleanField(_l('Show NSFL posts'))
|
||||
markdown_editor = BooleanField(_l('Use markdown editor GUI when writing'))
|
||||
searchable = BooleanField(_l('Show profile in user list'))
|
||||
indexable = BooleanField(_l('Allow search engines to index this profile'))
|
||||
indexable = BooleanField(_l('My posts appear in search results'))
|
||||
manually_approves_followers = BooleanField(_l('Manually approve followers'))
|
||||
import_file = FileField(_('Import community subscriptions and user blocks from Lemmy'))
|
||||
sorts = [('hot', _l('Hot')),
|
||||
|
|
|
@ -11,7 +11,8 @@ 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, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter
|
||||
Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter, Domain, DomainBlock, \
|
||||
InstanceBlock
|
||||
from app.user import bp
|
||||
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, FilterEditForm
|
||||
from app.user.utils import purge_user_then_delete
|
||||
|
@ -78,6 +79,7 @@ def show_profile(user):
|
|||
description=description, subscribed=subscribed, upvoted=upvoted,
|
||||
post_next_url=post_next_url, post_prev_url=post_prev_url,
|
||||
replies_next_url=replies_next_url, replies_prev_url=replies_prev_url,
|
||||
noindex=not user.indexable,
|
||||
moderating_communities=moderating_communities(current_user.get_id()),
|
||||
joined_communities=joined_communities(current_user.get_id())
|
||||
)
|
||||
|
@ -158,6 +160,7 @@ def change_settings():
|
|||
form = SettingsForm()
|
||||
form.theme.choices = theme_list()
|
||||
if form.validate_on_submit():
|
||||
propagate_indexable = form.indexable.data != current_user.indexable
|
||||
current_user.newsletter = form.newsletter.data
|
||||
current_user.ignore_bots = form.ignore_bots.data
|
||||
current_user.show_nsfw = form.nsfw.data
|
||||
|
@ -169,6 +172,10 @@ def change_settings():
|
|||
current_user.email_unread = form.email_unread.data
|
||||
current_user.markdown_editor = form.markdown_editor.data
|
||||
import_file = request.files['import_file']
|
||||
if propagate_indexable:
|
||||
db.session.execute(text('UPDATE "post" set indexable = :indexable WHERE user_id = :user_id'),
|
||||
{'user_id': current_user.id,
|
||||
'indexable': current_user.indexable})
|
||||
if import_file and import_file.filename != '':
|
||||
file_ext = os.path.splitext(import_file.filename)[1]
|
||||
if file_ext.lower() != '.json':
|
||||
|
@ -614,7 +621,17 @@ def import_settings_task(user_id, filename):
|
|||
@login_required
|
||||
def user_settings_filters():
|
||||
filters = Filter.query.filter_by(user_id=current_user.id).order_by(Filter.title).all()
|
||||
blocked_users = User.query.join(UserBlock, UserBlock.blocked_id == User.id).\
|
||||
filter(UserBlock.blocker_id == current_user.id).order_by(User.user_name).all()
|
||||
blocked_communities = Community.query.join(CommunityBlock, CommunityBlock.community_id == Community.id).\
|
||||
filter(CommunityBlock.user_id == current_user.id).order_by(Community.title).all()
|
||||
blocked_domains = Domain.query.join(DomainBlock, DomainBlock.domain_id == Domain.id).\
|
||||
filter(DomainBlock.user_id == current_user.id).order_by(Domain.name).all()
|
||||
blocked_instances = Instance.query.join(InstanceBlock, InstanceBlock.instance_id == Instance.id).\
|
||||
filter(InstanceBlock.user_id == current_user.id).order_by(Instance.domain).all()
|
||||
return render_template('user/filters.html', filters=filters, user=current_user,
|
||||
blocked_users=blocked_users, blocked_communities=blocked_communities,
|
||||
blocked_domains=blocked_domains, blocked_instances=blocked_instances,
|
||||
moderating_communities=moderating_communities(current_user.get_id()),
|
||||
joined_communities=joined_communities(current_user.get_id())
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ import re
|
|||
|
||||
from app.email import send_welcome_email
|
||||
from app.models import Settings, Domain, Instance, BannedInstances, User, Community, DomainBlock, ActivityPubLog, IpBan, \
|
||||
Site, Post, PostReply, utcnow, Filter, CommunityMember
|
||||
Site, Post, PostReply, utcnow, Filter, CommunityMember, InstanceBlock
|
||||
|
||||
|
||||
# Flask's render_template function, with support for themes added
|
||||
|
@ -313,6 +313,12 @@ def blocked_domains(user_id) -> List[int]:
|
|||
return [block.domain_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)
|
||||
return [block.instance_id for block in blocks]
|
||||
|
||||
|
||||
def retrieve_block_list():
|
||||
try:
|
||||
response = requests.get('https://raw.githubusercontent.com/rimu/no-qanon/master/domains.txt', timeout=1)
|
||||
|
|
Loading…
Reference in a new issue