mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-12-22 10:19:59 +00:00
Implement torrent nuking ability for mods (#377)
* Implement torrent nuking ability for mods This deletes all torrents of a specific user. A current caveat is that it will delete both sukebei and nyaa torrents, but will only leave a log entry in the current flavour's log. Also did some bootstrap untangling on the user view page. * Per-flavour logging Hopefully this works. Maybe. * Tracker API: chunk into 100-element sublists * isort * Restrict nuking to superadmins Also do a lint.sh.
This commit is contained in:
parent
de1fd2f1bc
commit
4019343d50
|
@ -333,25 +333,32 @@ def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
|
|||
|
||||
|
||||
def tracker_api(info_hashes, method):
|
||||
url = app.config.get('TRACKER_API_URL')
|
||||
if not url:
|
||||
api_url = app.config.get('TRACKER_API_URL')
|
||||
if not api_url:
|
||||
return False
|
||||
|
||||
qs = []
|
||||
qs.append(('auth', app.config.get('TRACKER_API_AUTH')))
|
||||
qs.append(('method', method))
|
||||
# Split list into at most 100 elements
|
||||
chunk_size = 100
|
||||
chunk_range = range(0, len(info_hashes), chunk_size)
|
||||
chunked_info_hashes = (info_hashes[i:i + chunk_size] for i in chunk_range)
|
||||
|
||||
for infohash in info_hashes:
|
||||
qs.append(('info_hash', infohash))
|
||||
for info_hashes_chunk in chunked_info_hashes:
|
||||
qs = [
|
||||
('auth', app.config.get('TRACKER_API_AUTH')),
|
||||
('method', method)
|
||||
]
|
||||
|
||||
qs = urlencode(qs)
|
||||
url += '?' + qs
|
||||
qs.extend(('info_hash', info_hash) for info_hash in info_hashes_chunk)
|
||||
|
||||
api_url += '?' + urlencode(qs)
|
||||
try:
|
||||
req = urlopen(url)
|
||||
req = urlopen(api_url)
|
||||
except:
|
||||
return False
|
||||
|
||||
return req.status == 200
|
||||
if req.status != 200:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _delete_cached_torrent_file(torrent_id):
|
||||
|
|
|
@ -265,6 +265,7 @@ class DeleteForm(FlaskForm):
|
|||
class BanForm(FlaskForm):
|
||||
ban_user = SubmitField("Delete & Ban and Ban User")
|
||||
ban_userip = SubmitField("Delete & Ban and Ban User+IP")
|
||||
nuke = SubmitField("Delete & Ban all torrents")
|
||||
unban = SubmitField("Unban")
|
||||
|
||||
_validator = DataRequired()
|
||||
|
|
|
@ -55,48 +55,71 @@
|
|||
</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ ban_form.csrf_token }}
|
||||
{% if user.is_banned %}
|
||||
This user is <strong>banned</strong>.<br>
|
||||
This user is <strong>banned</strong>.
|
||||
{% endif %}
|
||||
{% if ipbanned %}
|
||||
This user is <strong>ip banned</strong>.<br>
|
||||
This user is <strong>ip banned</strong>.
|
||||
{% endif %}
|
||||
{% if not user.is_banned and not bans %}
|
||||
This user is <strong>not banned</strong>.<br>
|
||||
This user is <strong>not banned</strong>.
|
||||
{% endif %}
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
{% if user.is_banned or bans %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>
|
||||
{% for ban in bans %}
|
||||
#{{ ban.id }}
|
||||
by <a href="{{ url_for('users.view_user', user_name=ban.admin.username) }}">{{ ban.admin.username }}</a>
|
||||
for <span markdown-text-inline>{{ ban.reason }}</span>
|
||||
<br>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ ban_form.unban(class="btn btn-info") }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not user.is_banned or not ipbanned %}
|
||||
{% if user.is_banned or bans %}
|
||||
<hr>
|
||||
{% endif %}
|
||||
<div class="row" style="margin-top:1.5em">
|
||||
<div class="col-md-12">
|
||||
{{ render_field(ban_form.reason, class_="form-control", placeholder="Specify a ban reason.") }}<br>
|
||||
<div class="pull-left">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 text-left">
|
||||
{% if not user.is_banned %}
|
||||
{{ ban_form.ban_user(value="Ban User", class="btn btn-danger") }}
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-danger disabled">Already banned</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="col-md-4 text-center">
|
||||
{% if not ipbanned %}
|
||||
{{ ban_form.ban_userip(value="Ban User+IP", class="btn btn-danger") }}
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-danger disabled">Already IP banned</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
{% if g.user.is_superadmin %}
|
||||
{{ ban_form.nuke(value="\U0001F4A3 Nuke Torrents", class="btn btn-danger") }}
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-danger disabled">💣 Nuke Torrents</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
@ -106,10 +129,12 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h3>
|
||||
<div class="row">
|
||||
<h3>
|
||||
Browsing <span class="text-{{ user.userlevel_color }}" data-toggle="tooltip" title="{{ user.userlevel_str }}">{{ user.username }}</span>'{{ '' if user.username[-1] == 's' else 's' }} torrents
|
||||
</h3>
|
||||
</h3>
|
||||
|
||||
{% include "search_results.html" %}
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
|
|
@ -2,13 +2,14 @@ import binascii
|
|||
import math
|
||||
import time
|
||||
from ipaddress import ip_address
|
||||
from itertools import chain
|
||||
|
||||
import flask
|
||||
from flask_paginate import Pagination
|
||||
|
||||
from itsdangerous import BadSignature, URLSafeSerializer
|
||||
|
||||
from nyaa import forms, models
|
||||
from nyaa import backend, forms, models
|
||||
from nyaa.extensions import db
|
||||
from nyaa.search import (DEFAULT_MAX_SEARCH_RESULT, DEFAULT_PER_PAGE, SERACH_PAGINATE_DISPLAY_MSG,
|
||||
_generate_query_string, search_db, search_elastic)
|
||||
|
@ -102,6 +103,41 @@ def view_user(user_name):
|
|||
flask.flash(flask.Markup('User has been successfully {0}.'.format(action)), 'success')
|
||||
return flask.redirect(url)
|
||||
|
||||
if flask.request.method == 'POST' and ban_form and ban_form.nuke.data:
|
||||
if flask.g.user.is_superadmin:
|
||||
nyaa_banned = 0
|
||||
sukebei_banned = 0
|
||||
info_hashes = []
|
||||
for t in chain(user.nyaa_torrents, user.sukebei_torrents):
|
||||
t.deleted = True
|
||||
t.banned = True
|
||||
info_hashes.append([t.info_hash])
|
||||
db.session.add(t)
|
||||
if isinstance(t, models.NyaaTorrent):
|
||||
nyaa_banned += 1
|
||||
else:
|
||||
sukebei_banned += 1
|
||||
|
||||
if info_hashes:
|
||||
backend.tracker_api(info_hashes, 'ban')
|
||||
|
||||
for log_flavour, num in ((models.NyaaAdminLog, nyaa_banned),
|
||||
(models.SukebeiAdminLog, sukebei_banned)):
|
||||
if num > 0:
|
||||
log = "Nuked {0} torrents of [{1}]({2})".format(num,
|
||||
user.username,
|
||||
url)
|
||||
adminlog = log_flavour(log=log, admin_id=flask.g.user.id)
|
||||
db.session.add(adminlog)
|
||||
|
||||
db.session.commit()
|
||||
flask.flash('Torrents of {0} have been nuked.'.format(user.username),
|
||||
'success')
|
||||
return flask.redirect(url)
|
||||
else:
|
||||
flask.flash('Insufficient permissions to nuke.', 'danger')
|
||||
return flask.redirect(url)
|
||||
|
||||
req_args = flask.request.args
|
||||
|
||||
search_term = chain_get(req_args, 'q', 'term')
|
||||
|
|
Loading…
Reference in a new issue