diff --git a/nyaa/forms.py b/nyaa/forms.py index 8e83fd8..32e772b 100644 --- a/nyaa/forms.py +++ b/nyaa/forms.py @@ -282,7 +282,8 @@ class ReportForm(FlaskForm): reason = TextAreaField('Report reason', [ Length(min=3, max=255, message='Report reason must be at least %(min)d characters long ' - 'and %(max)d at most.') + 'and %(max)d at most.'), + DataRequired('You must provide a valid report reason.') ]) diff --git a/nyaa/models.py b/nyaa/models.py index 7ba57f7..e098ffa 100644 --- a/nyaa/models.py +++ b/nyaa/models.py @@ -13,6 +13,7 @@ from urllib.parse import unquote as unquote_url if app.config['USE_MYSQL']: from sqlalchemy.dialects import mysql + BinaryType = mysql.BINARY DescriptionTextType = mysql.TEXT MediumBlobType = mysql.MEDIUMBLOB @@ -27,7 +28,6 @@ else: COL_UTF8MB4_BIN = None COL_ASCII_GENERAL_CI = 'NOCASE' - # For property timestamps UTC_EPOCH = datetime.utcfromtimestamp(0) @@ -327,6 +327,7 @@ class User(db.Model): last_login_ip = db.Column(db.Binary(length=16), default=None, nullable=True) torrents = db.relationship('Torrent', back_populates='user', lazy="dynamic") + # session = db.relationship('Session', uselist=False, back_populates='user') def __init__(self, username, email, password): @@ -398,8 +399,8 @@ class Report(db.Model): reason = db.Column(db.String(length=255), nullable=False) status = db.Column(ChoiceType(ReportStatus, impl=db.Integer()), nullable=False) - user = db.relationship('User', uselist=False) - torrent = db.relationship('Torrent', uselist=False) + user = db.relationship('User', uselist=False, lazy="joined") + torrent = db.relationship('Torrent', uselist=False, lazy="joined") def __init__(self, torrent_id, user_id, reason): self.torrent_id = torrent_id @@ -416,8 +417,16 @@ class Report(db.Model): return (self.created_time - UTC_EPOCH).total_seconds() @classmethod - def not_reviewed(cls): - reports = cls.query.filter_by(status=0).all() + def by_id(cls, id): + return cls.query.get(id) + + @classmethod + def not_reviewed(cls, page): + reports = cls.query.filter(cls.status == 0)\ + .join(Torrent, aliased=True).filter(Torrent.flags != 36, Torrent.flags != 2)\ + .order_by(db.asc(cls.id))\ + .paginate(page=page, per_page=20) + # reports = cls.query.filter_by(status=0).paginate(page=page, per_page=20) return reports # class Session(db.Model): diff --git a/nyaa/routes.py b/nyaa/routes.py index 4b03588..401b639 100644 --- a/nyaa/routes.py +++ b/nyaa/routes.py @@ -27,7 +27,6 @@ from email.utils import formatdate from flask_paginate import Pagination - DEBUG_API = False DEFAULT_MAX_SEARCH_RESULT = 1000 DEFAULT_PER_PAGE = 75 @@ -582,7 +581,7 @@ def view_torrent(torrent_id): return flask.render_template('view.html', torrent=torrent, files=files, can_edit=can_edit, - form=report_form) + report_form=report_form) @app.route('/view//edit', methods=['GET', 'POST']) @@ -667,34 +666,54 @@ def download_torrent(torrent_id): @app.route('/view//submit_report', methods=['POST']) def submit_report(torrent_id): + if not flask.g.user: + flask.abort(403) + form = forms.ReportForm(flask.request.form) if flask.request.method == 'POST' and form.validate(): - report_reason = (form.reason.data or '').strip() + report_reason = form.reason.data + current_user_id = flask.g.user.id + report = models.Report( + torrent_id=torrent_id, + user_id=current_user_id, + reason=report_reason) - if flask.g.user is not None: - current_user_id = flask.g.user.id - report = models.Report( - torrent_id=torrent_id, - user_id=current_user_id, - reason=report_reason) - - db.session.add(report) - db.session.commit() - flask.flash('Successfully reported torrent!', 'success') - else: - flask.abort(403) + db.session.add(report) + db.session.commit() + flask.flash('Successfully reported torrent!', 'success') return flask.redirect(flask.url_for('view_torrent', torrent_id=torrent_id)) -@app.route('/reports', methods=['GET']) +@app.route('/reports', methods=['GET', 'POST']) def view_reports(): - reports = models.Report.not_reviewed() - if not flask.g.user or not flask.g.user.is_admin: flask.abort(403) + page = flask.request.args.get('p', flask.request.args.get('offset', 1, int), int) + reports = models.Report.not_reviewed(page) + + if flask.request.method == 'POST': + data = flask.request.form + torrent = models.Torrent.by_id(data['torrent']) + report = models.Report.by_id(data['report']) + if not torrent or not report or report.status != 0: + flask.abort(404) + else: + if data['action'] == 'delete': + torrent.deleted = True + report.status = 1 + elif data['action'] == 'hide': + torrent.hidden = True + report.status = 1 + else: + report.status = 2 + + db.session.commit() + flask.flash('Closed report #{}'.format(report.id), 'success') + return flask.redirect(flask.url_for('view_reports')) + return flask.render_template('reports.html', reports=reports) diff --git a/nyaa/templates/reports.html b/nyaa/templates/reports.html index 91d7dcb..6b85840 100644 --- a/nyaa/templates/reports.html +++ b/nyaa/templates/reports.html @@ -2,29 +2,50 @@ {% block title %}Reports :: {{ config.SITE_NAME }}{% endblock %} {% block body %} {% from "_formhelpers.html" import render_field %} -
- - - - - - - - - - - - - {% for report in reports %} - - - - - - - - {% endfor %} - -
#Reported by:Torrent:Reason:Date:Action:
{{ report.id }}{{ report.user.username }}{{ report.torrent.display_name }}{{ report.reason }}{{ report.created_time }}
-
+
+ + + + + + + + + + + + + {% for report in reports.items %} + + + + + + + + + {% endfor %} + +
#Reported byTorrentReasonDateAction
{{ report.id }} + {{ report.user.username }} + + {{ report.torrent.display_name }} + {{ report.reason }}{{ report.created_time }} +
+ + + + +
+
+
+ + {% endblock %} diff --git a/nyaa/templates/view.html b/nyaa/templates/view.html index bc98df5..ca778a4 100644 --- a/nyaa/templates/view.html +++ b/nyaa/templates/view.html @@ -2,158 +2,179 @@ {% block title %}{{ torrent.display_name }} :: {{ config.SITE_NAME }}{% endblock %} {% block body %} {% from "_formhelpers.html" import render_field %} -
-
-

- {% if can_edit %} - - {% endif %} - {{ torrent.display_name }} -

-
-
-
-
Category:
- - -
Date:
-
{{ torrent.created_time.strftime('%Y-%m-%d %H:%M UTC') }}
+
+
+

+ {% if can_edit %} + + {% endif %} + {{ torrent.display_name }} +

- -
-
Submitter:
-
{% if not torrent.anonymous and torrent.user %}{{ torrent.user.username }}{% else %}Anonymous{% endif %}
- -
Seeders:
-
{% if config.ENABLE_SHOW_STATS %}{{ torrent.stats.seed_count }}{% else %}Coming soon{% endif %}
- -
- -
-
Information:
-
- {% if torrent.information %} - {{ torrent.information_as_link | safe }} - {% else %} - No information. - {% endif%} -
- -
Leechers:
-
{% if config.ENABLE_SHOW_STATS %}{{ torrent.stats.leech_count }}{% else %}Coming soon{% endif %}
-
- -
-
File size:
-
{{ torrent.filesize | filesizeformat(True) }}
- -
Downloads:
-
{% if config.ENABLE_SHOW_STATS %}{{ torrent.stats.download_count }}{% else %}Coming soon{% endif %}
-
-
- -
- -
-
- {% if torrent.description %} - {# Escape newlines into html entities because CF strips blank newlines #} - {{ torrent.description | escape | replace('\r\n', '\n') | replace('\n', ' '|safe) }} - {% else %} - #### No description. - {% endif%} -
-
- -{% if files and files.__len__() <= config.MAX_FILES_VIEW %} -
-
-

+
- +
Category:
+ + +
Date:
+
{{ torrent.created_time.strftime('%Y-%m-%d %H:%M UTC') }}
-

+ +
+
Submitter:
+
{% if not torrent.anonymous and torrent.user %} + {{ torrent.user.username }}{% else %} + Anonymous{% endif %}
+ +
Seeders:
+
{% if config.ENABLE_SHOW_STATS %} + {{ torrent.stats.seed_count }}{% else %}Coming soon{% endif %}
+ +
+ +
+
Information:
+
+ {% if torrent.information %} + {{ torrent.information_as_link | safe }} + {% else %} + No information. + {% endif %} +
+ +
Leechers:
+
{% if config.ENABLE_SHOW_STATS %} + {{ torrent.stats.leech_count }}{% else %}Coming soon{% endif %}
+
+ +
+
File size:
+
{{ torrent.filesize | filesizeformat(True) }}
+ +
Downloads:
+
+ {% if config.ENABLE_SHOW_STATS %}{{ torrent.stats.download_count }}{% else %}Coming + soon{% endif %}
+
+
+
-
- - - - - - - {%- for key, value in files.items() recursive %} - - {%- if value is iterable %} - - {{ loop(value.items()) }} - {%- else %} - -  {{ key }} - - {%- endif %} - - {%- endfor %} -
PathSize
-   {{ key }}{{ value | filesizeformat(True) }}
+
+
+ {% if torrent.description %} + {# Escape newlines into html entities because CF strips blank newlines #} + {{ torrent.description | escape | replace('\r\n', '\n') | replace('\n', ' '|safe) }} + {% else %} + #### No description. + {% endif %} +
-
-{% elif files %} -
-
-

-
Too many files to display.
-

+ + {% if files and files.__len__() <= config.MAX_FILES_VIEW %} +
+
+

+
+ +
+

+
+ +
+ + + + + + + {%- for key, value in files.items() recursive %} + + {%- if value is iterable %} + + {{ loop(value.items()) }} + {%- else %} + +  {{ key }} + + {%- endif %} + + {%- endfor %} +
PathSize
+   {{ key }}{{ value | filesizeformat(True) }}
+
+
+ {% elif files %} +
+
+

+
+
Too many files to display.
+
+

+
+
+ {% else %} +
+
+

+
+
File list is not available for this torrent.
+
+

+
+
+ {% endif %} + + -
-{% else %} -
-
-

-
File list is not available for this torrent.
-

-
-
-{% endif %} - - - + {% endblock %}