domain block and ban

This commit is contained in:
rimu 2024-02-02 16:52:23 +13:00
parent d4ea6aba0e
commit 888cce94fc
4 changed files with 160 additions and 14 deletions

View file

@ -3,14 +3,16 @@ from flask_login import login_user, logout_user, current_user, login_required
from flask_babel import _ from flask_babel import _
from app import db, constants from app import db, constants
from app.models import Post, Domain, Community from app.models import Post, Domain, Community, DomainBlock
from app.domain import bp from app.domain import bp
from app.utils import get_setting, render_template from app.utils import get_setting, render_template, permission_required
from sqlalchemy import desc from sqlalchemy import desc
@bp.route('/d/<domain_id>', methods=['GET']) @bp.route('/d/<domain_id>', methods=['GET'])
def show_domain(domain_id): def show_domain(domain_id):
page = request.args.get('page', 1, type=int)
if '.' in domain_id: if '.' in domain_id:
domain = Domain.query.filter_by(name=domain_id, banned=False).first() domain = Domain.query.filter_by(name=domain_id, banned=False).first()
else: else:
@ -23,16 +25,81 @@ def show_domain(domain_id):
filter(Post.from_bot == False, Post.domain_id == domain.id, Community.banned == False).\ filter(Post.from_bot == False, Post.domain_id == domain.id, Community.banned == False).\
order_by(desc(Post.last_active)).all() order_by(desc(Post.last_active)).all()
else: else:
posts = Post.query.join(Community).filter(Post.domain_id == domain.id, Community.banned == False).order_by(desc(Post.last_active)).all() posts = Post.query.join(Community).filter(Post.domain_id == domain.id, Community.banned == False).order_by(desc(Post.last_active))
# todo: pagination # pagination
posts = posts.paginate(page=page, per_page=100, error_out=False)
next_url = url_for('main.index', page=posts.next_num) if posts.has_next else None
prev_url = url_for('main.index', page=posts.prev_num) if posts.has_prev and page != 1 else None
return render_template('domain/domain.html', domain=domain, title=domain.name, posts=posts, return render_template('domain/domain.html', domain=domain, title=domain.name, posts=posts,
POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE, POST_TYPE_LINK=constants.POST_TYPE_LINK) POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE, POST_TYPE_LINK=constants.POST_TYPE_LINK,
next_url=next_url, prev_url=prev_url)
else: else:
abort(404) abort(404)
@bp.route('/domains', methods=['GET']) @bp.route('/domains', methods=['GET'])
def domains(): def domains():
domains = Domain.query.filter_by(banned=False).order_by(Domain.name).all() page = request.args.get('page', 1, type=int)
search = request.args.get('search', '')
return render_template('domain/domains.html', title='All known domains', domains=domains) domains = Domain.query.filter_by(banned=False)
if search != '':
domains = domains.filter(Domain.name.ilike(f'%{search}%'))
domains = domains.order_by(Domain.name)
domains = domains.paginate(page=page, per_page=100, error_out=False)
next_url = url_for('main.index', page=domains.next_num) if domains.has_next else None
prev_url = url_for('main.index', page=domains.prev_num) if domains.has_prev and page != 1 else None
return render_template('domain/domains.html', title='All known domains', domains=domains,
next_url=next_url, prev_url=prev_url, search=search)
@bp.route('/d/<int:domain_id>/block')
@login_required
def domain_block(domain_id):
domain = Domain.query.get_or_404(domain_id)
block = DomainBlock.query.filter_by(user_id=current_user.id, domain_id=domain_id).first()
if not block:
block = DomainBlock(user_id=current_user.id, domain_id=domain_id)
db.session.add(block)
db.session.commit()
flash(_('%(name)s blocked.', name=domain.name))
return redirect(url_for('domain.show_domain', domain_id=domain.id))
@bp.route('/d/<int:domain_id>/unblock')
@login_required
def domain_unblock(domain_id):
domain = Domain.query.get_or_404(domain_id)
block = DomainBlock.query.filter_by(user_id=current_user.id, domain_id=domain_id).first()
if not block:
db.session.delete(block)
db.session.commit()
flash(_('%(name)s un-blocked.', name=domain.name))
return redirect(url_for('domain.show_domain', domain_id=domain.id))
@bp.route('/d/<int:domain_id>/ban')
@login_required
@permission_required('manage users')
def domain_ban(domain_id):
domain = Domain.query.get_or_404(domain_id)
if domain:
domain.banned = True
db.session.commit()
domain.purge_content()
flash(_('%(name)s banned for all users and all content deleted.', name=domain.name))
return redirect(url_for('domain.domains'))
@bp.route('/d/<int:domain_id>/unban')
@login_required
@permission_required('manage users')
def domain_unban(domain_id):
domain = Domain.query.get_or_404(domain_id)
if domain:
domain.banned = True
db.session.commit()
flash(_('%(name)s un-banned for all users.', name=domain.name))
return redirect(url_for('domain.show_domain', domain_id=domain.id))

View file

@ -796,6 +796,21 @@ class Domain(db.Model):
notify_mods = db.Column(db.Boolean, default=False, index=True) notify_mods = db.Column(db.Boolean, default=False, index=True)
notify_admins = db.Column(db.Boolean, default=False, index=True) notify_admins = db.Column(db.Boolean, default=False, index=True)
def blocked_by(self, user):
block = DomainBlock.query.filter_by(domain_id=self.id, user_id=user.id).first()
return block is not None
def purge_content(self):
files = File.query.join(Post).filter(Post.domain_id == self.id).all()
for file in files:
file.delete_from_disk()
posts = Post.query.filter_by(domain_id=self.id).all()
for post in posts:
post.delete_dependencies()
post.flush_cache()
db.session.delete(post)
db.session.commit()
class DomainBlock(db.Model): class DomainBlock(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)

View file

@ -19,10 +19,64 @@
<p>{{ _('No posts in this domain yet.') }}</p> <p>{{ _('No posts in this domain yet.') }}</p>
{% endfor %} {% endfor %}
</div> </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">&larr;</span> {{ _('Previous page') }}
</a>
{% endif %}
{% if next_url %}
<a href="{{ next_url }}" class="btn btn-primary" rel='nofollow'>
{{ _('Next page') }} <span aria-hidden="true">&rarr;</span>
</a>
{% endif %}
</nav>
</div> </div>
<aside class="col-12 col-md-4 side_pane" role="complementary"> <aside class="col-12 col-md-4 side_pane" role="complementary">
{% if current_user.is_authenticated %}
<div class="card mt-3">
<div class="card-header">
<h2>{{ _('Domain management') }}</h2>
</div>
<div class="card-body">
<div class="row">
{% if domain.blocked_by(current_user) %}
<div class="col-4">
<a class="w-100 btn btn-primary" href="/d/{{ domain.id }}/unblock">{{ _('Unblock') }}</a>
</div>
{% else %}
<div class="col-4">
<a class="w-100 btn btn-primary" href="/d/{{ domain.id }}/block">{{ _('Block') }}</a>
</div>
{% endif %}
</div>
</div>
</div>
{% if user_access('ban users', current_user.id) or user_access('manage users', current_user.id) %}
<div class="card mt-3">
<div class="card-header">
<h2>{{ _('Domain management') }}</h2>
</div>
<div class="card-body">
<div class="row">
{% if domain.banned %}
<div class="col-8">
<a class="w-100 btn btn-primary confirm_first" href="/d/{{ domain.id }}/unban">{{ _('Unban') }}</a>
</div>
{% else %}
<div class="col-8">
<a class="w-100 btn btn-primary confirm_first" href="/d/{{ domain.id }}/ban">{{ _('Ban instance-wide') }}</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
{% endif %}
{% include "_inoculation_links.html" %}
</aside> </aside>
</div> </div>
<div class="row"> <div class="row">

View file

@ -10,16 +10,26 @@
<li class="breadcrumb-item active">Domains</li> <li class="breadcrumb-item active">Domains</li>
</ol> </ol>
</nav> </nav>
{% if search == '' %}
<h1 class="mt-2">{{ _('All known domains') }}</h1> <h1 class="mt-2">{{ _('All known domains') }}</h1>
<div class="post_list"> {% else %}
<ul> <h1 class="mt-2">{{ _('Domains containing %(search)s', search=search) }}</h1>
{% endif %}
<form method="get"><input type="search" name="search" value="{{ search }}" placeholder="{{ _('Search') }}" autofocus></form>
<table class="table table-striped">
<thead>
<tr>
<th>{{ _('Domain') }}</th>
</tr>
</thead>
<tbody>
{% for domain in domains %} {% for domain in domains %}
<li> <tr>
<a href="{{ url_for('domain.show_domain', domain_id=domain.id) }}">{{ domain.name }}</a> <th><a href="{{ url_for('domain.show_domain', domain_id=domain.id) }}">{{ domain.name }}</a></th>
</li> </tr>
{% endfor %} {% endfor %}
</ul> </tbody>
</div> </table>
</div> </div>
<aside class="col-12 col-md-4 side_pane" role="complementary"> <aside class="col-12 col-md-4 side_pane" role="complementary">