mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-24 11:51:27 -08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
6fb566c14e
16 changed files with 267 additions and 91 deletions
|
@ -18,6 +18,8 @@ from sqlalchemy_searchable import make_searchable
|
|||
|
||||
from config import Config
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def get_locale():
|
||||
try:
|
||||
|
@ -97,12 +99,6 @@ def create_app(config_class=Config):
|
|||
from app.search import bp as search_bp
|
||||
app.register_blueprint(search_bp)
|
||||
|
||||
def get_resource_as_string(name, charset='utf-8'):
|
||||
with app.open_resource(name) as f:
|
||||
return f.read().decode(charset)
|
||||
|
||||
app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string
|
||||
|
||||
# send error reports via email
|
||||
if app.config['MAIL_SERVER'] and app.config['MAIL_ERRORS']:
|
||||
auth = None
|
||||
|
|
|
@ -175,12 +175,12 @@ def user_profile(actor):
|
|||
actor = actor.strip()
|
||||
if current_user.is_authenticated and current_user.is_admin():
|
||||
if '@' in actor:
|
||||
user: User = User.query.filter_by(ap_id=actor.lower()).first()
|
||||
user: User = User.query.filter_by(ap_id=actor).first()
|
||||
else:
|
||||
user: User = User.query.filter_by(user_name=actor, ap_id=None).first()
|
||||
else:
|
||||
if '@' in actor:
|
||||
user: User = User.query.filter_by(ap_id=actor.lower(), deleted=False, banned=False).first()
|
||||
user: User = User.query.filter_by(ap_id=actor, deleted=False, banned=False).first()
|
||||
else:
|
||||
user: User = User.query.filter_by(user_name=actor, deleted=False, ap_id=None).first()
|
||||
|
||||
|
|
|
@ -98,6 +98,11 @@ def register():
|
|||
if form.user_name.data in disallowed_usernames:
|
||||
flash(_('Sorry, you cannot use that user name'), 'error')
|
||||
else:
|
||||
# Nazis use 88 and 14 in their user names very often.
|
||||
if '88' in form.user_name.data or '14' in form.user_name.data:
|
||||
resp = make_response(redirect(url_for('auth.please_wait')))
|
||||
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
||||
return resp
|
||||
for referrer in blocked_referrers():
|
||||
if referrer in session.get('Referer', ''):
|
||||
resp = make_response(redirect(url_for('auth.please_wait')))
|
||||
|
|
|
@ -947,17 +947,30 @@ def community_moderate(actor):
|
|||
abort(404)
|
||||
|
||||
|
||||
@bp.route('/<actor>/moderate/banned', methods=['GET'])
|
||||
@bp.route('/<actor>/moderate/subscribers', methods=['GET'])
|
||||
@login_required
|
||||
def community_moderate_banned(actor):
|
||||
def community_moderate_subscribers(actor):
|
||||
community = actor_to_community(actor)
|
||||
|
||||
if community is not None:
|
||||
if community.is_moderator() or current_user.is_admin():
|
||||
|
||||
page = request.args.get('page', 1, type=int)
|
||||
low_bandwidth = request.cookies.get('low_bandwidth', '0') == '1'
|
||||
|
||||
subscribers = User.query.join(CommunityMember, CommunityMember.user_id == User.id).filter(CommunityMember.community_id == community.id)
|
||||
subscribers = subscribers.filter(CommunityMember.is_banned == False)
|
||||
|
||||
# Pagination
|
||||
subscribers = subscribers.paginate(page=page, per_page=100 if not low_bandwidth else 50, error_out=False)
|
||||
next_url = url_for('community.community_moderate_subscribers', actor=actor, page=subscribers.next_num) if subscribers.has_next else None
|
||||
prev_url = url_for('community.community_moderate_subscribers', actor=actor, page=subscribers.prev_num) if subscribers.has_prev and page != 1 else None
|
||||
|
||||
banned_people = User.query.join(CommunityBan, CommunityBan.user_id == User.id).filter(CommunityBan.community_id == community.id).all()
|
||||
return render_template('community/community_moderate_banned.html',
|
||||
title=_('People banned from of %(community)s', community=community.display_name()),
|
||||
community=community, banned_people=banned_people, current='banned',
|
||||
|
||||
return render_template('community/community_moderate_subscribers.html', title=_('Moderation of %(community)s', community=community.display_name()),
|
||||
community=community, current='subscribers', subscribers=subscribers, banned_people=banned_people,
|
||||
next_url=next_url, prev_url=prev_url, low_bandwidth=low_bandwidth,
|
||||
moderating_communities=moderating_communities(current_user.get_id()),
|
||||
joined_communities=joined_communities(current_user.get_id()),
|
||||
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||
|
@ -1023,3 +1036,41 @@ def community_moderate_report_resolve(community_id, report_id):
|
|||
return redirect(url_for('community.community_moderate', actor=community.link()))
|
||||
else:
|
||||
return render_template('community/community_moderate_report_resolve.html', form=form)
|
||||
|
||||
|
||||
@bp.route('/lookup/<community>/<domain>')
|
||||
def lookup(community, domain):
|
||||
if domain == current_app.config['SERVER_NAME']:
|
||||
return redirect('/c/' + community)
|
||||
|
||||
exists = Community.query.filter_by(name=community, ap_domain=domain).first()
|
||||
if exists:
|
||||
return redirect('/c/' + community + '@' + domain)
|
||||
else:
|
||||
address = '!' + community + '@' + domain
|
||||
if current_user.is_authenticated:
|
||||
new_community = None
|
||||
|
||||
new_community = search_for_community(address)
|
||||
if new_community is None:
|
||||
if g.site.enable_nsfw:
|
||||
flash(_('Community not found.'), 'warning')
|
||||
else:
|
||||
flash(_('Community not found. If you are searching for a nsfw community it is blocked by this instance.'), 'warning')
|
||||
else:
|
||||
if new_community.banned:
|
||||
flash(_('That community is banned from %(site)s.', site=g.site.name), 'warning')
|
||||
|
||||
return render_template('community/lookup_remote.html',
|
||||
title=_('Search result for remote community'), new_community=new_community,
|
||||
subscribed=community_membership(current_user, new_community) >= SUBSCRIPTION_MEMBER)
|
||||
else:
|
||||
# send them back where they came from
|
||||
flash('Searching for remote communities requires login', 'error')
|
||||
referrer = request.headers.get('Referer', None)
|
||||
if referrer is not None:
|
||||
return redirect(referrer)
|
||||
else:
|
||||
return redirect('/')
|
||||
|
||||
|
||||
|
|
|
@ -920,6 +920,8 @@ fieldset legend {
|
|||
position: relative;
|
||||
cursor: pointer;
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
.voting_buttons_new .upvote_button.digits_4, .voting_buttons_new .downvote_button.digits_4 {
|
||||
width: 68px;
|
||||
|
@ -987,7 +989,7 @@ fieldset legend {
|
|||
.voting_buttons {
|
||||
float: right;
|
||||
display: block;
|
||||
width: 55px;
|
||||
min-width: 54px;
|
||||
padding: 0 0 5px 5px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
|
@ -1002,9 +1004,13 @@ fieldset legend {
|
|||
}
|
||||
.voting_buttons .upvote_button, .voting_buttons .downvote_button {
|
||||
position: relative;
|
||||
padding-left: 3px;
|
||||
padding: 0 3px;
|
||||
min-height: 44px;
|
||||
min-width: 44px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.voting_buttons .upvote_button.digits_4, .voting_buttons .downvote_button.digits_4 {
|
||||
width: 68px;
|
||||
|
|
|
@ -5,6 +5,8 @@ nav, etc which are used site-wide */
|
|||
@import "scss/typography";
|
||||
@import "scss/controls";
|
||||
|
||||
$min-touch-target: 44px;
|
||||
|
||||
html {
|
||||
@include breakpoint(phablet) {
|
||||
scroll-padding-top: 80px;
|
||||
|
@ -553,6 +555,8 @@ html {
|
|||
position: relative;
|
||||
cursor: pointer;
|
||||
color: rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));
|
||||
min-width: $min-touch-target;
|
||||
min-height: $min-touch-target;
|
||||
|
||||
&.digits_4 {
|
||||
width: 68px;
|
||||
|
@ -625,7 +629,7 @@ html {
|
|||
.voting_buttons {
|
||||
float: right;
|
||||
display: block;
|
||||
width: 55px;
|
||||
min-width: $min-touch-target + 10;
|
||||
padding: 0 0 5px 5px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
|
@ -640,9 +644,13 @@ html {
|
|||
|
||||
.upvote_button, .downvote_button {
|
||||
position: relative;
|
||||
padding-left: 3px;
|
||||
padding: 0 3px;
|
||||
min-height: $min-touch-target;
|
||||
min-width: $min-touch-target;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.digits_4 {
|
||||
width: 68px;
|
||||
|
|
|
@ -426,6 +426,10 @@ fieldset legend {
|
|||
background-color: #d8e5ee;
|
||||
}
|
||||
|
||||
html, body {
|
||||
overscroll-behavior-x: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
@import "scss/typography";
|
||||
@import "scss/controls";
|
||||
|
||||
html, body {
|
||||
overscroll-behavior-x: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
@ -14,6 +18,7 @@ a {
|
|||
}
|
||||
|
||||
#outer_container, footer {
|
||||
//overscroll-behavior-x: none;
|
||||
a:not(.btn):hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="btn-group mt-3 mb-2">
|
||||
<div class="btn-group mt-3 mb-2 flex-wrap">
|
||||
{% if community.is_owner() or current_user.is_admin() %}
|
||||
<a href="{{ url_for('community.community_edit', community_id=community.id) }}" class="btn {{ 'btn-primary' if current == '' or current == 'edit_settings' else 'btn-outline-secondary' }}" rel="nofollow noindex">
|
||||
{{ _('Settings') }}
|
||||
|
@ -10,8 +10,8 @@
|
|||
<a href="/community/{{ community.link() }}/moderate" aria-label="{{ _('Sort by hot') }}" class="btn {{ 'btn-primary' if current == '' or current == 'reports' else 'btn-outline-secondary' }}" rel="nofollow noindex">
|
||||
{{ _('Reports') }}
|
||||
</a>
|
||||
<a href="/community/{{ community.link() }}/moderate/banned" class="btn {{ 'btn-primary' if current == 'banned' else 'btn-outline-secondary' }}" rel="nofollow noindex">
|
||||
{{ _('Banned people') }}
|
||||
<a href="/community/{{ community.link() }}/moderate/subscribers" class="btn {{ 'btn-primary' if current == 'subscribers' else 'btn-outline-secondary' }}" rel="nofollow noindex">
|
||||
{{ _('Subscribers') }}
|
||||
</a>
|
||||
<a href="/community/{{ community.link() }}/moderate/appeals" class="btn {{ 'btn-primary' if current == 'appeals' else 'btn-outline-secondary' }} disabled" rel="nofollow noindex" >
|
||||
{{ _('Appeals') }}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||
{% extends 'themes/' + theme() + '/base.html' %}
|
||||
{% else %}
|
||||
{% extends "base.html" %}
|
||||
{% endif %} %}
|
||||
{% from 'bootstrap/form.html' import render_field %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 position-relative main_pane">
|
||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not none else community.name) }}">{{ (community.title + '@' + community.ap_domain)|shorten }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ _('Moderation') }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
{% include "community/_community_moderation_nav.html" %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-10">
|
||||
<h1 class="mt-2">{{ _('Banned people') }}</h1>
|
||||
</div>
|
||||
<div class="col-12 col-md-2 text-right">
|
||||
<!-- <a class="btn btn-primary" href="{{ url_for('community.community_add_moderator', community_id=community.id) }}">{{ _('Add moderator') }}</a> -->
|
||||
</div>
|
||||
</div>
|
||||
<p>{{ _('See and manage who is banned from %(community)s', community=community.display_name()) }}</p>
|
||||
<h2></h2>
|
||||
{% if banned_people %}
|
||||
<form method="get">
|
||||
<input type="search" name="search" value="{{ search }}">
|
||||
<input type="radio" name="local_remote" value="local" id="local_remote_local" {{ 'checked' if local_remote == 'local' }}><label for="local_remote_local"> Local</label>
|
||||
<input type="radio" name="local_remote" value="remote" id="local_remote_remote" {{ 'checked' if local_remote == 'remote' }}><label for="local_remote_remote"> Remote</label>
|
||||
<input type="submit" name="submit" value="Search" class="btn btn-primary">
|
||||
</form>
|
||||
<table class="table table-striped mt-1">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Local/Remote</th>
|
||||
<th>Reports</th>
|
||||
<th>IP</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
{% for user in banned_people %}
|
||||
<tr>
|
||||
<td><img src="{{ user.avatar_thumbnail() }}" class="community_icon rounded-circle" loading="lazy" />
|
||||
{{ user.display_name() }}</td>
|
||||
<td>{{ 'Local' if user.is_local() else 'Remote' }}</td>
|
||||
<td>{{ user.reports if user.reports > 0 }} </td>
|
||||
<td>{{ user.ip_address if user.ip_address }} </td>
|
||||
<td>{% if user.is_local() %}
|
||||
<a href="/u/{{ user.link() }}">View</a>
|
||||
{% else %}
|
||||
<a href="/u/{{ user.link() }}">View local</a> |
|
||||
<a href="{{ user.ap_profile_id }}">View remote</a>
|
||||
{% endif %}
|
||||
| <a href="{{ url_for('community.community_unban_user', community_id=community.id, user_id=user.id) }}" class="confirm_first">{{ _('Un ban') }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>{{ _('No banned people yet') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
129
app/templates/community/community_moderate_subscribers.html
Normal file
129
app/templates/community/community_moderate_subscribers.html
Normal file
|
@ -0,0 +1,129 @@
|
|||
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||
{% extends 'themes/' + theme() + '/base.html' %}
|
||||
{% else %}
|
||||
{% extends "base.html" %}
|
||||
{% endif %} %}
|
||||
{% from 'bootstrap/form.html' import render_field %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 position-relative main_pane">
|
||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not none else community.name) }}">{{ (community.title + '@' + community.ap_domain)|shorten }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ _('Moderation') }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
{% include "community/_community_moderation_nav.html" %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-10">
|
||||
<h1 class="mt-2">{{ _('Subscribers') }}</h1>
|
||||
</div>
|
||||
<div class="col-12 col-md-2 text-right">
|
||||
<!-- <a class="btn btn-primary" href="{{ url_for('community.community_add_moderator', community_id=community.id) }}">{{ _('Add moderator') }}</a> -->
|
||||
</div>
|
||||
</div>
|
||||
<p>{{ _('See who is subscribed to %(community)s', community=community.display_name()) }}</p>
|
||||
<h2></h2>
|
||||
{% if subscribers %}
|
||||
<div class="table-responsive-lg">
|
||||
<table class="table table-striped mt-1">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Local/Remote</th>
|
||||
<th>Last Seen</th>
|
||||
<th>IP</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
{% for user in subscribers.items %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/u/{{ user.link() }}">{{ render_username(user) }}</a>
|
||||
</td>
|
||||
<td>{% if user.is_local() %} Local {% else %} <a href="{{ user.ap_profile_id }}">{{ user.ap_domain }}</a>{% endif %}</td>
|
||||
<td>{{ moment(user.last_seen).fromNow() }} </td>
|
||||
<td>{{ user.ip_address if user.ip_address }} </td>
|
||||
<td>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Actions
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% if user.is_local() %}<li><a class="dropdown-item" href="/chat/{{ user.id }}/new">Send Message</a></li>{% endif %}
|
||||
<li><a class="dropdown-item" href="/u/{{ user.link() }}/report">Report</a></li>
|
||||
<div class="dropdown-divider"></div>
|
||||
<li><a class="dropdown-item" href="{{ url_for('community.community_ban_user', community_id=community.id, user_id=user.id) }}" class="confirm_first">{{ _('Ban') }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<nav aria-label="Pagination" class="mt-4" role="navigation">
|
||||
{% if prev_url %}
|
||||
<a href="{{ prev_url }}" class="btn btn-primary" rel="nofollow">
|
||||
<span aria-hidden="true">←</span> {{ _('Previous page') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if next_url %}
|
||||
<a href="{{ next_url }}" class="btn btn-primary" rel="nofollow">
|
||||
{{ _('Next page') }} <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% else %}
|
||||
<p>{{ _('This community has no subscribers') }}</p>
|
||||
{% endif %}
|
||||
<h1 class="mt-2">{{ _('Banned People') }}</h1>
|
||||
<p>{{ _('See and manage who is banned from %(community)s', community=community.display_name()) }}</p>
|
||||
{% if banned_people %}
|
||||
<form method="get">
|
||||
<input type="search" name="search" value="{{ search }}">
|
||||
<input type="radio" name="local_remote" value="local" id="local_remote_local" {{ 'checked' if local_remote == 'local' }}><label for="local_remote_local"> Local</label>
|
||||
<input type="radio" name="local_remote" value="remote" id="local_remote_remote" {{ 'checked' if local_remote == 'remote' }}><label for="local_remote_remote"> Remote</label>
|
||||
<input type="submit" name="submit" value="Search" class="btn btn-primary">
|
||||
</form>
|
||||
<div class="table-responsive-lg">
|
||||
<table class="table table-striped mt-1">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Local/Remote</th>
|
||||
<th>Reports</th>
|
||||
<th>IP</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
{% for user in banned_people %}
|
||||
<tr>
|
||||
<td><a href="/u/{{ user.link() }}">{{ render_username(user) }}</a></td>
|
||||
<td>{% if user.is_local() %} Local {% else %} <a href="{{ user.ap_profile_id }}">{{ user.ap_domain }}</a>{% endif %}</td>
|
||||
<td>{{ user.reports if user.reports > 0 }} </td>
|
||||
<td>{{ user.ip_address if user.ip_address }} </td>
|
||||
<td>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Actions
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% if user.is_local() %}<li><a class="dropdown-item" href="/chat/{{ user.id }}/new">Send Message</a></li>
|
||||
<li><a class="dropdown-item" href="/u/{{ user.link() }}">View</a></li>
|
||||
{% else %}
|
||||
<li><a class="dropdown-item" href="/u/{{ user.link() }}">View local</a> </li>
|
||||
<li><a class="dropdown-item"href="{{ user.ap_profile_id }}">View remote</a></li>
|
||||
{% endif %}
|
||||
<div class="dropdown-divider"></div>
|
||||
<li><a class="dropdown-item" href="{{ url_for('community.community_unban_user', community_id=community.id, user_id=user.id) }}" class="confirm_first">{{ _('Unban') }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>{{ _('No banned people yet') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
32
app/templates/community/lookup_remote.html
Normal file
32
app/templates/community/lookup_remote.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||
{% extends 'themes/' + theme() + '/base.html' %}
|
||||
{% else %}
|
||||
{% extends "base.html" %}
|
||||
{% endif %} %}
|
||||
{% from 'bootstrap/form.html' import render_form %}
|
||||
|
||||
{% block app_content %}
|
||||
{% if new_community and not new_community.banned %}
|
||||
<div class="row">
|
||||
<div class="col mx-auto">
|
||||
<div class="card mt-5">
|
||||
<div class="card-body p-6">
|
||||
<div class="card-title">{{ _('Found a community:') }}</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
<a href="/c/{{ new_community.link() }}"><img src="{{ new_community.icon_image()}}" class="community_icon rounded-circle" style="width: 30px; vertical-align: middle;" /></a>
|
||||
<a href="/c/{{ new_community.link() }}">{{ new_community.title }}@{{ new_community.ap_domain }}</a>
|
||||
</p>
|
||||
<p> {% if subscribed %}
|
||||
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/unsubscribe">{{ _('Leave') }}</a>
|
||||
{% else %}
|
||||
<a class="btn btn-primary mt-4" href="/community/{{ new_community.link() }}/subscribe">{{ _('Join') }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -42,7 +42,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="post_body mt-2">
|
||||
{{ post.body_html|safe if post.body_html else '' }}
|
||||
{{ post.body_html|community_links|safe if post.body_html else '' }}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
@ -99,7 +99,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="post_body">
|
||||
{{ post.body_html|safe if post.body_html else '' }}
|
||||
{{ post.body_html|community_links|safe if post.body_html else '' }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
{% endif %}
|
||||
</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 }}
|
||||
{{ comment['comment'].body_html | community_links | safe }}
|
||||
</div>{% if not comment['comment'].author.indexable %}<!--googleon: all-->{% endif %}
|
||||
</div>
|
||||
<div class="comment_actions hidable">
|
||||
|
|
|
@ -252,6 +252,12 @@ def microblog_content_to_title(html: str) -> str:
|
|||
return result
|
||||
|
||||
|
||||
def community_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'/community/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:
|
||||
parsed_url = urlparse(url.lower().replace('www.', ''))
|
||||
if parsed_url and parsed_url.hostname:
|
||||
|
|
|
@ -11,7 +11,7 @@ from flask import session, g, json, request, current_app
|
|||
from app.constants import POST_TYPE_LINK, POST_TYPE_IMAGE, POST_TYPE_ARTICLE
|
||||
from app.models import Site
|
||||
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
|
||||
can_create_post, can_upvote, can_downvote, shorten_number, ap_datetime, current_theme, community_link_to_href
|
||||
|
||||
app = create_app()
|
||||
cli.register(app)
|
||||
|
@ -44,6 +44,7 @@ with app.app_context():
|
|||
app.jinja_env.globals['can_downvote'] = can_downvote
|
||||
app.jinja_env.globals['theme'] = current_theme
|
||||
app.jinja_env.globals['file_exists'] = os.path.exists
|
||||
app.jinja_env.filters['community_links'] = community_link_to_href
|
||||
app.jinja_env.filters['shorten'] = shorten_string
|
||||
app.jinja_env.filters['shorten_url'] = shorten_url
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue