mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
mentions in comments - recognise @user@instance syntax in UI
This commit is contained in:
parent
250405aafb
commit
385bd6bfbe
6 changed files with 89 additions and 14 deletions
|
@ -36,7 +36,6 @@ from app.models import User, Community, CommunityMember, CommunityJoinRequest, C
|
||||||
NotificationSubscription, UserFollower, Instance, Language, Poll, PollChoice, ModLog, CommunityWikiPage, \
|
NotificationSubscription, UserFollower, Instance, Language, Poll, PollChoice, ModLog, CommunityWikiPage, \
|
||||||
CommunityWikiPageRevision, read_posts
|
CommunityWikiPageRevision, read_posts
|
||||||
from app.community import bp
|
from app.community import bp
|
||||||
from app.user.utils import search_for_user
|
|
||||||
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
||||||
shorten_string, gibberish, community_membership, ap_datetime, \
|
shorten_string, gibberish, community_membership, ap_datetime, \
|
||||||
request_etag_matches, return_304, instance_banned, can_create_post, can_upvote, can_downvote, user_filters_posts, \
|
request_etag_matches, return_304, instance_banned, can_create_post, can_upvote, can_downvote, user_filters_posts, \
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
<p>Deleted by author</p>
|
<p>Deleted by author</p>
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
{% else -%}
|
{% else -%}
|
||||||
{{ post_reply.body_html | community_links | safe }}
|
{{ post_reply.body_html | community_links | person_links | safe }}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@ from app.models import Post, Community, CommunityMember, User, PostReply, PostVo
|
||||||
from app.user import bp
|
from app.user import bp
|
||||||
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, \
|
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, \
|
||||||
FilterForm, KeywordFilterEditForm, RemoteFollowForm, ImportExportForm, UserNoteForm
|
FilterForm, KeywordFilterEditForm, RemoteFollowForm, ImportExportForm, UserNoteForm
|
||||||
from app.user.utils import purge_user_then_delete, unsubscribe_from_community
|
from app.user.utils import purge_user_then_delete, unsubscribe_from_community, search_for_user
|
||||||
from app.utils import get_setting, render_template, markdown_to_html, user_access, markdown_to_text, shorten_string, \
|
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, \
|
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, \
|
user_filters_posts, user_filters_replies, moderating_communities, joined_communities, theme_list, blocked_instances, \
|
||||||
|
@ -1381,3 +1381,40 @@ def user_preview(user_id):
|
||||||
if (user.deleted or user.banned) and current_user.is_anonymous:
|
if (user.deleted or user.banned) and current_user.is_anonymous:
|
||||||
abort(404)
|
abort(404)
|
||||||
return render_template('user/user_preview.html', user=user)
|
return render_template('user/user_preview.html', user=user)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/user/lookup/<person>/<domain>')
|
||||||
|
def lookup(person, domain):
|
||||||
|
if domain == current_app.config['SERVER_NAME']:
|
||||||
|
return redirect('/u/' + person)
|
||||||
|
|
||||||
|
exists = User.query.filter_by(user_name=person, ap_domain=domain).first()
|
||||||
|
if exists:
|
||||||
|
return redirect('/u/' + person + '@' + domain)
|
||||||
|
else:
|
||||||
|
address = '@' + person + '@' + domain
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
new_person = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_person = search_for_user(address)
|
||||||
|
except Exception as e:
|
||||||
|
if 'is blocked.' in str(e):
|
||||||
|
flash(_('Sorry, that instance is blocked, check https://gui.fediseer.com/ for reasons.'), 'warning')
|
||||||
|
if not new_person or new_person.banned:
|
||||||
|
flash(_('That person could not be retreived or is banned from %(site)s.', site=g.site.name), 'warning')
|
||||||
|
referrer = request.headers.get('Referer', None)
|
||||||
|
if referrer is not None:
|
||||||
|
return redirect(referrer)
|
||||||
|
else:
|
||||||
|
return redirect('/')
|
||||||
|
|
||||||
|
return redirect('/u/' + new_person.ap_id)
|
||||||
|
else:
|
||||||
|
# send them back where they came from
|
||||||
|
flash('Searching for remote people requires login', 'error')
|
||||||
|
referrer = request.headers.get('Referer', None)
|
||||||
|
if referrer is not None:
|
||||||
|
return redirect(referrer)
|
||||||
|
else:
|
||||||
|
return redirect('/')
|
||||||
|
|
|
@ -3,12 +3,14 @@ from time import sleep
|
||||||
from flask import current_app, json
|
from flask import current_app, json
|
||||||
|
|
||||||
from app import celery, db
|
from app import celery, db
|
||||||
from app.activitypub.signature import post_request, default_context
|
from app.activitypub.signature import post_request, default_context, signed_get_request
|
||||||
from app.activitypub.util import actor_json_to_model
|
from app.activitypub.util import actor_json_to_model
|
||||||
from app.community.util import send_to_remote_instance
|
from app.community.util import send_to_remote_instance
|
||||||
from app.models import User, CommunityMember, Community, Instance, Site, utcnow, ActivityPubLog, BannedInstances
|
from app.models import User, CommunityMember, Community, Instance, Site, utcnow, ActivityPubLog, BannedInstances
|
||||||
from app.utils import gibberish, ap_datetime, instance_banned, get_request
|
from app.utils import gibberish, ap_datetime, instance_banned, get_request
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
def purge_user_then_delete(user_id):
|
def purge_user_then_delete(user_id):
|
||||||
if current_app.debug:
|
if current_app.debug:
|
||||||
|
@ -140,17 +142,47 @@ def search_for_user(address: str):
|
||||||
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
||||||
params={'resource': f"acct:{address}"})
|
params={'resource': f"acct:{address}"})
|
||||||
if webfinger_data.status_code == 200:
|
if webfinger_data.status_code == 200:
|
||||||
webfinger_json = webfinger_data.json()
|
try:
|
||||||
|
webfinger_json = webfinger_data.json()
|
||||||
|
webfinger_data.close()
|
||||||
|
except:
|
||||||
|
webfinger_data.close()
|
||||||
|
return None
|
||||||
for links in webfinger_json['links']:
|
for links in webfinger_json['links']:
|
||||||
if 'rel' in links and links['rel'] == 'self': # this contains the URL of the activitypub profile
|
if 'rel' in links and links['rel'] == 'self': # this contains the URL of the activitypub profile
|
||||||
type = links['type'] if 'type' in links else 'application/activity+json'
|
type = links['type'] if 'type' in links else 'application/activity+json'
|
||||||
# retrieve the activitypub profile
|
# retrieve the activitypub profile
|
||||||
user_data = get_request(links['href'], headers={'Accept': type})
|
for attempt in [1,2]:
|
||||||
# to see the structure of the json contained in community_data, do a GET to https://lemmy.world/c/technology with header Accept: application/activity+json
|
try:
|
||||||
if user_data.status_code == 200:
|
object_request = get_request(links['href'], headers={'Accept': type})
|
||||||
user_json = user_data.json()
|
except httpx.HTTPError:
|
||||||
user_data.close()
|
if attempt == 1:
|
||||||
if user_json['type'] == 'Person' or user_json['type'] == 'Service':
|
time.sleep(3)
|
||||||
user = actor_json_to_model(user_json, name, server)
|
else:
|
||||||
return user
|
return None
|
||||||
|
if object_request.status_code == 401:
|
||||||
|
site = Site.query.get(1)
|
||||||
|
for attempt in [1,2]:
|
||||||
|
try:
|
||||||
|
object_request = signed_get_request(links['href'], site.private_key, f"https://{current_app.config['SERVER_NAME']}/actor#main-key")
|
||||||
|
except httpx.HTTPError:
|
||||||
|
if attempt == 1:
|
||||||
|
time.sleep(3)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
if object_request.status_code == 200:
|
||||||
|
try:
|
||||||
|
object = object_request.json()
|
||||||
|
object_request.close()
|
||||||
|
except:
|
||||||
|
object_request.close()
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if object['type'] == 'Person' or object['type'] == 'Service':
|
||||||
|
user = actor_json_to_model(object, name, server)
|
||||||
|
return user
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -456,6 +456,12 @@ def community_link_to_href(link: str) -> str:
|
||||||
return re.sub(pattern, server + r'\g<1>/\g<2>>' + r'!\g<1>@\g<2></a>', link)
|
return re.sub(pattern, server + r'\g<1>/\g<2>>' + r'!\g<1>@\g<2></a>', link)
|
||||||
|
|
||||||
|
|
||||||
|
def person_link_to_href(link: str) -> str:
|
||||||
|
pattern = r"@([a-zA-Z0-9_.-]*)@([a-zA-Z0-9_.-]*)\b"
|
||||||
|
server = r'<a href=https://' + current_app.config['SERVER_NAME'] + r'/user/lookup/'
|
||||||
|
return re.sub(pattern, server + r'\g<1>/\g<2>>' + r'@\g<1>@\g<2></a>', link)
|
||||||
|
|
||||||
|
|
||||||
def domain_from_url(url: str, create=True) -> Domain:
|
def domain_from_url(url: str, create=True) -> Domain:
|
||||||
parsed_url = urlparse(url.lower().replace('www.', ''))
|
parsed_url = urlparse(url.lower().replace('www.', ''))
|
||||||
if parsed_url and parsed_url.hostname:
|
if parsed_url and parsed_url.hostname:
|
||||||
|
|
|
@ -13,7 +13,7 @@ from app.constants import POST_TYPE_LINK, POST_TYPE_IMAGE, POST_TYPE_ARTICLE, PO
|
||||||
from app.models import Site
|
from app.models import Site
|
||||||
from app.utils import getmtime, gibberish, shorten_string, shorten_url, digits, user_access, community_membership, \
|
from app.utils import getmtime, gibberish, shorten_string, shorten_url, digits, user_access, community_membership, \
|
||||||
can_create_post, can_upvote, can_downvote, shorten_number, ap_datetime, current_theme, community_link_to_href, \
|
can_create_post, can_upvote, can_downvote, shorten_number, ap_datetime, current_theme, community_link_to_href, \
|
||||||
in_sorted_list, role_access, first_paragraph
|
in_sorted_list, role_access, first_paragraph, person_link_to_href
|
||||||
|
|
||||||
app = create_app()
|
app = create_app()
|
||||||
cli.register(app)
|
cli.register(app)
|
||||||
|
@ -54,6 +54,7 @@ with app.app_context():
|
||||||
app.jinja_env.globals['file_exists'] = os.path.exists
|
app.jinja_env.globals['file_exists'] = os.path.exists
|
||||||
app.jinja_env.globals['first_paragraph'] = first_paragraph
|
app.jinja_env.globals['first_paragraph'] = first_paragraph
|
||||||
app.jinja_env.filters['community_links'] = community_link_to_href
|
app.jinja_env.filters['community_links'] = community_link_to_href
|
||||||
|
app.jinja_env.filters['person_links'] = person_link_to_href
|
||||||
app.jinja_env.filters['shorten'] = shorten_string
|
app.jinja_env.filters['shorten'] = shorten_string
|
||||||
app.jinja_env.filters['shorten_url'] = shorten_url
|
app.jinja_env.filters['shorten_url'] = shorten_url
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue