diff --git a/nyaa/backend.py b/nyaa/backend.py index fdff17a..523a8b6 100644 --- a/nyaa/backend.py +++ b/nyaa/backend.py @@ -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 - try: - req = urlopen(url) - except: - return False + qs.extend(('info_hash', info_hash) for info_hash in info_hashes_chunk) - return req.status == 200 + api_url += '?' + urlencode(qs) + try: + req = urlopen(api_url) + except: + return False + + if req.status != 200: + return False + return True def _delete_cached_torrent_file(torrent_id): diff --git a/nyaa/forms.py b/nyaa/forms.py index 045fe3d..f2c1de7 100644 --- a/nyaa/forms.py +++ b/nyaa/forms.py @@ -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() diff --git a/nyaa/templates/user.html b/nyaa/templates/user.html index 8526c34..a1c3dba 100644 --- a/nyaa/templates/user.html +++ b/nyaa/templates/user.html @@ -55,47 +55,70 @@
- {{ ban_form.csrf_token }} - {% if user.is_banned %} - This user is banned.
- {% endif %} - {% if ipbanned %} - This user is ip banned.
- {% endif %} - {% if not user.is_banned and not bans %} - This user is not banned.
- {% endif %} -
+
+
+ {{ ban_form.csrf_token }} + {% if user.is_banned %} + This user is banned. + {% endif %} + {% if ipbanned %} + This user is ip banned. + {% endif %} + {% if not user.is_banned and not bans %} + This user is not banned. + {% endif %} +
+
{% if user.is_banned or bans %} -

- {% for ban in bans %} - #{{ ban.id }} - by {{ ban.admin.username }} - for {{ ban.reason }} -
- {% endfor %} -

- {{ ban_form.unban(class="btn btn-info") }} +
+
+

+ {% for ban in bans %} + #{{ ban.id }} + by {{ ban.admin.username }} + for {{ ban.reason }} + {% endfor %} +

+
+
+
+
+ {{ ban_form.unban(class="btn btn-info") }} +
+
{% endif %} {% if not user.is_banned or not ipbanned %} {% if user.is_banned or bans %}
{% endif %} - {{ render_field(ban_form.reason, class_="form-control", placeholder="Specify a ban reason.") }}
-
- {% if not user.is_banned %} - {{ ban_form.ban_user(value="Ban User", class="btn btn-danger") }} - {% else %} - - {% endif %} +
+
+ {{ render_field(ban_form.reason, class_="form-control", placeholder="Specify a ban reason.") }}
+
-
- {% if not ipbanned %} - {{ ban_form.ban_userip(value="Ban User+IP", class="btn btn-danger") }} - {% else %} - - {% endif %} +
+
+ {% if not user.is_banned %} + {{ ban_form.ban_user(value="Ban User", class="btn btn-danger") }} + {% else %} + + {% endif %} +
+
+ {% if not ipbanned %} + {{ ban_form.ban_userip(value="Ban User+IP", class="btn btn-danger") }} + {% else %} + + {% endif %} +
+
+ {% if g.user.is_superadmin %} + {{ ban_form.nuke(value="\U0001F4A3 Nuke Torrents", class="btn btn-danger") }} + {% else %} + + {% endif %} +
{% endif %} @@ -106,10 +129,12 @@
{% endif %} -

- Browsing {{ user.username }}'{{ '' if user.username[-1] == 's' else 's' }} torrents -

+
+

+ Browsing {{ user.username }}'{{ '' if user.username[-1] == 's' else 's' }} torrents +

{% include "search_results.html" %} {% endblock %} +
diff --git a/nyaa/views/users.py b/nyaa/views/users.py index 838daf8..7a95dd1 100644 --- a/nyaa/views/users.py +++ b/nyaa/views/users.py @@ -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')