mirror of
				https://github.com/sb745/NyaaV3.git
				synced 2025-11-04 01:45:46 +02:00 
			
		
		
		
	[DB Changes!] Merge branch 'nyaazi-reports' (#146)
Adds reporting functionality. Alembic migration included.
This commit is contained in:
		
						commit
						7b2bfc57ee
					
				
					 14 changed files with 286 additions and 7 deletions
				
			
		
							
								
								
									
										0
									
								
								WSGI.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								WSGI.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								migrations/README
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								migrations/README
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								migrations/env.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								migrations/env.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								migrations/script.py.mako
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								migrations/script.py.mako
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										56
									
								
								migrations/versions/7f064e009cab_add_report_table.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								migrations/versions/7f064e009cab_add_report_table.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
"""Add Report table
 | 
			
		||||
 | 
			
		||||
Revision ID: 7f064e009cab
 | 
			
		||||
Revises: 2bceb2cb4d7c
 | 
			
		||||
Create Date: 2017-05-29 16:50:28.720980
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision = '7f064e009cab'
 | 
			
		||||
down_revision = '2bceb2cb4d7c'
 | 
			
		||||
branch_labels = None
 | 
			
		||||
depends_on = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.create_table('nyaa_reports',
 | 
			
		||||
        sa.Column('id', sa.Integer(), nullable=False),
 | 
			
		||||
        sa.Column('created_time', sa.DateTime(), nullable=True),
 | 
			
		||||
        sa.Column('reason', sa.String(length=255), nullable=False),
 | 
			
		||||
 | 
			
		||||
        # sqlalchemy_utils.types.choice.ChoiceType()
 | 
			
		||||
        sa.Column('status', sa.Integer(), nullable=False),
 | 
			
		||||
 | 
			
		||||
        sa.Column('torrent_id', sa.Integer(), nullable=False),
 | 
			
		||||
        sa.Column('user_id', sa.Integer(), nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['torrent_id'], ['nyaa_torrents.id'], ondelete='CASCADE'),
 | 
			
		||||
        sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
 | 
			
		||||
        sa.PrimaryKeyConstraint('id')
 | 
			
		||||
    )
 | 
			
		||||
    op.create_table('sukebei_reports',
 | 
			
		||||
        sa.Column('id', sa.Integer(), nullable=False),
 | 
			
		||||
        sa.Column('created_time', sa.DateTime(), nullable=True),
 | 
			
		||||
        sa.Column('reason', sa.String(length=255), nullable=False),
 | 
			
		||||
 | 
			
		||||
        # sqlalchemy_utils.types.choice.ChoiceType()
 | 
			
		||||
        sa.Column('status', sa.Integer(), nullable=False),
 | 
			
		||||
 | 
			
		||||
        sa.Column('torrent_id', sa.Integer(), nullable=False),
 | 
			
		||||
        sa.Column('user_id', sa.Integer(), nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['torrent_id'], ['sukebei_torrents.id'], ondelete='CASCADE'),
 | 
			
		||||
        sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
 | 
			
		||||
        sa.PrimaryKeyConstraint('id')
 | 
			
		||||
    )
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.drop_table('sukebei_reports')
 | 
			
		||||
    op.drop_table('nyaa_reports')
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,8 @@ import os
 | 
			
		|||
import re
 | 
			
		||||
from flask_wtf import FlaskForm
 | 
			
		||||
from flask_wtf.file import FileField, FileRequired
 | 
			
		||||
from wtforms import StringField, PasswordField, BooleanField, TextAreaField, SelectField
 | 
			
		||||
from wtforms import StringField, PasswordField, BooleanField, TextAreaField, SelectField,\
 | 
			
		||||
    HiddenField
 | 
			
		||||
from wtforms.validators import DataRequired, Optional, Email, Length, EqualTo, ValidationError
 | 
			
		||||
from wtforms.validators import Regexp
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -295,6 +296,21 @@ class TorrentFileData(object):
 | 
			
		|||
# https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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.'),
 | 
			
		||||
        DataRequired('You must provide a valid report reason.')
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReportActionForm(FlaskForm):
 | 
			
		||||
    action = SelectField(choices=[('close', 'Close'), ('hide', 'Hide'), ('delete', 'Delete')])
 | 
			
		||||
    torrent = HiddenField()
 | 
			
		||||
    report = HiddenField()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate_trackers(torrent_dict, tracker_to_check_for=None):
 | 
			
		||||
    announce = torrent_dict.get('announce')
 | 
			
		||||
    announce_string = _validate_bytes(announce, 'announce', test_decode='utf-8')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								nyaa/models.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										70
									
								
								nyaa/models.py
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -580,6 +580,65 @@ class User(db.Model):
 | 
			
		|||
        return self.level >= UserLevelType.TRUSTED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReportStatus(IntEnum):
 | 
			
		||||
    IN_REVIEW = 0
 | 
			
		||||
    VALID = 1
 | 
			
		||||
    INVALID = 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReportBase(DeclarativeHelperBase):
 | 
			
		||||
    __tablename_base__ = 'reports'
 | 
			
		||||
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)
 | 
			
		||||
    created_time = db.Column(db.DateTime(timezone=False), default=datetime.utcnow)
 | 
			
		||||
    reason = db.Column(db.String(length=255), nullable=False)
 | 
			
		||||
    status = db.Column(ChoiceType(ReportStatus, impl=db.Integer()), nullable=False)
 | 
			
		||||
 | 
			
		||||
    @declarative.declared_attr
 | 
			
		||||
    def torrent_id(cls):
 | 
			
		||||
        return db.Column(db.Integer, db.ForeignKey(
 | 
			
		||||
            cls._table_prefix('torrents.id'), ondelete='CASCADE'), nullable=False)
 | 
			
		||||
 | 
			
		||||
    @declarative.declared_attr
 | 
			
		||||
    def user_id(cls):
 | 
			
		||||
        return db.Column(db.Integer, db.ForeignKey('users.id'))
 | 
			
		||||
 | 
			
		||||
    @declarative.declared_attr
 | 
			
		||||
    def user(cls):
 | 
			
		||||
        return db.relationship('User', uselist=False, lazy="joined")
 | 
			
		||||
 | 
			
		||||
    @declarative.declared_attr
 | 
			
		||||
    def torrent(cls):
 | 
			
		||||
        return db.relationship(cls._flavor_prefix('Torrent'), uselist=False, lazy="joined")
 | 
			
		||||
 | 
			
		||||
    def __init__(self, torrent_id, user_id, reason):
 | 
			
		||||
        self.torrent_id = torrent_id
 | 
			
		||||
        self.user_id = user_id
 | 
			
		||||
        self.reason = reason
 | 
			
		||||
        self.status = ReportStatus.IN_REVIEW
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '<Report %r>' % self.id
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def created_utc_timestamp(self):
 | 
			
		||||
        ''' Returns a UTC POSIX timestamp, as seconds '''
 | 
			
		||||
        return (self.created_time - UTC_EPOCH).total_seconds()
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def by_id(cls, id):
 | 
			
		||||
        return cls.query.get(id)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def not_reviewed(cls, page):
 | 
			
		||||
        reports = cls.query.filter_by(status=0).paginate(page=page, per_page=20)
 | 
			
		||||
        return reports
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def remove_reviewed(cls, id):
 | 
			
		||||
        return cls.query.filter(cls.torrent_id == id, cls.status == 0).delete()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Actually declare our site-specific classes
 | 
			
		||||
 | 
			
		||||
# Torrent
 | 
			
		||||
| 
						 | 
				
			
			@ -672,6 +731,15 @@ class SukebeiComment(CommentBase, db.Model):
 | 
			
		|||
    __flavor__ = 'Sukebei'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Report
 | 
			
		||||
class NyaaReport(ReportBase, db.Model):
 | 
			
		||||
    __flavor__ = 'Nyaa'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SukebeiReport(ReportBase, db.Model):
 | 
			
		||||
    __flavor__ = 'Sukebei'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Choose our defaults for models.Torrent etc
 | 
			
		||||
if app.config['SITE_FLAVOR'] == 'nyaa':
 | 
			
		||||
    Torrent = NyaaTorrent
 | 
			
		||||
| 
						 | 
				
			
			@ -682,6 +750,7 @@ if app.config['SITE_FLAVOR'] == 'nyaa':
 | 
			
		|||
    MainCategory = NyaaMainCategory
 | 
			
		||||
    SubCategory = NyaaSubCategory
 | 
			
		||||
    Comment = NyaaComment
 | 
			
		||||
    Report = NyaaReport
 | 
			
		||||
 | 
			
		||||
    TorrentNameSearch = NyaaTorrentNameSearch
 | 
			
		||||
elif app.config['SITE_FLAVOR'] == 'sukebei':
 | 
			
		||||
| 
						 | 
				
			
			@ -693,5 +762,6 @@ elif app.config['SITE_FLAVOR'] == 'sukebei':
 | 
			
		|||
    MainCategory = SukebeiMainCategory
 | 
			
		||||
    SubCategory = SukebeiSubCategory
 | 
			
		||||
    Comment = SukebeiComment
 | 
			
		||||
    Report = SukebeiReport
 | 
			
		||||
 | 
			
		||||
    TorrentNameSearch = SukebeiTorrentNameSearch
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,6 @@ from email.utils import formatdate
 | 
			
		|||
 | 
			
		||||
from flask_paginate import Pagination
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DEBUG_API = False
 | 
			
		||||
DEFAULT_MAX_SEARCH_RESULT = 1000
 | 
			
		||||
DEFAULT_PER_PAGE = 75
 | 
			
		||||
| 
						 | 
				
			
			@ -675,11 +674,13 @@ def view_torrent(torrent_id):
 | 
			
		|||
    if torrent.filelist:
 | 
			
		||||
        files = json.loads(torrent.filelist.filelist_blob.decode('utf-8'))
 | 
			
		||||
 | 
			
		||||
    report_form = forms.ReportForm()
 | 
			
		||||
    return flask.render_template('view.html', torrent=torrent,
 | 
			
		||||
                                 files=files,
 | 
			
		||||
                                 comment_form=comment_form,
 | 
			
		||||
                                 comments=torrent.comments,
 | 
			
		||||
                                 can_edit=can_edit)
 | 
			
		||||
                                 can_edit=can_edit,
 | 
			
		||||
                                 report_form=report_form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/view/<int:torrent_id>/comment/<int:comment_id>/delete', methods=['POST'])
 | 
			
		||||
| 
						 | 
				
			
			@ -798,6 +799,66 @@ def download_torrent(torrent_id):
 | 
			
		|||
    return resp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/view/<int:torrent_id>/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
 | 
			
		||||
        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')
 | 
			
		||||
 | 
			
		||||
    return flask.redirect(flask.url_for('view_torrent', torrent_id=torrent_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/reports', methods=['GET', 'POST'])
 | 
			
		||||
def view_reports():
 | 
			
		||||
    if not flask.g.user or not flask.g.user.is_moderator:
 | 
			
		||||
        flask.abort(403)
 | 
			
		||||
 | 
			
		||||
    page = flask.request.args.get('p', flask.request.args.get('offset', 1, int), int)
 | 
			
		||||
    reports = models.Report.not_reviewed(page)
 | 
			
		||||
    report_action = forms.ReportActionForm(flask.request.form)
 | 
			
		||||
 | 
			
		||||
    if flask.request.method == 'POST' and report_action.validate():
 | 
			
		||||
        action = report_action.action.data
 | 
			
		||||
        torrent_id = report_action.torrent.data
 | 
			
		||||
        report_id = report_action.report.data
 | 
			
		||||
        torrent = models.Torrent.by_id(torrent_id)
 | 
			
		||||
        report = models.Report.by_id(report_id)
 | 
			
		||||
 | 
			
		||||
        if not torrent or not report or report.status != 0:
 | 
			
		||||
            flask.abort(404)
 | 
			
		||||
        else:
 | 
			
		||||
            if action == 'delete':
 | 
			
		||||
                torrent.deleted = True
 | 
			
		||||
                report.status = 1
 | 
			
		||||
            elif action == 'hide':
 | 
			
		||||
                torrent.hidden = True
 | 
			
		||||
                report.status = 1
 | 
			
		||||
            else:
 | 
			
		||||
                report.status = 2
 | 
			
		||||
 | 
			
		||||
            models.Report.remove_reviewed(torrent_id)
 | 
			
		||||
            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,
 | 
			
		||||
                                 report_action=report_action)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_cached_torrent_file(torrent):
 | 
			
		||||
    # Note: obviously temporary
 | 
			
		||||
    cached_torrent = os.path.join(app.config['BASE_DIR'],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										0
									
								
								nyaa/static/css/main.css
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								nyaa/static/css/main.css
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								nyaa/templates/edit.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								nyaa/templates/edit.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										5
									
								
								nyaa/templates/layout.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										5
									
								
								nyaa/templates/layout.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -88,6 +88,9 @@
 | 
			
		|||
						{% elif config.SITE_FLAVOR == 'sukebei' %}
 | 
			
		||||
						<li><a href="https://nyaa.si/">Fun</a></li>
 | 
			
		||||
						{% endif %}
 | 
			
		||||
						{% if g.user.is_moderator %}
 | 
			
		||||
							<li><a href="{{ url_for('view_reports') }}">Reports</a> </li>
 | 
			
		||||
						{% endif %}
 | 
			
		||||
					</ul>
 | 
			
		||||
 | 
			
		||||
					<ul class="nav navbar-nav navbar-right">
 | 
			
		||||
| 
						 | 
				
			
			@ -304,5 +307,3 @@
 | 
			
		|||
		</footer>
 | 
			
		||||
	</body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								nyaa/templates/reports.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								nyaa/templates/reports.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
{% extends "layout.html" %}
 | 
			
		||||
{% block title %}Reports :: {{ config.SITE_NAME }}{% endblock %}
 | 
			
		||||
{% block body %}
 | 
			
		||||
{% from "_formhelpers.html" import render_field %}
 | 
			
		||||
	<div class="table-responsive">
 | 
			
		||||
		<table class="table table-bordered table-hover table-striped">
 | 
			
		||||
			<thead>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<th>#</th>
 | 
			
		||||
				<th>Reported by</th>
 | 
			
		||||
				<th>Torrent</th>
 | 
			
		||||
				<th>Reason</th>
 | 
			
		||||
				<th>Date</th>
 | 
			
		||||
				<th>Action</th>
 | 
			
		||||
			</tr>
 | 
			
		||||
			</thead>
 | 
			
		||||
			<tbody>
 | 
			
		||||
			{% for report in reports.items %}
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>{{ report.id }}</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<a href="{{ url_for('view_user', user_name=report.user.username) }}">{{ report.user.username }}</a>
 | 
			
		||||
				</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<a href="{{ url_for('view_torrent', torrent_id=report.torrent.id) }}">{{ report.torrent.display_name }}</a>
 | 
			
		||||
				</td>
 | 
			
		||||
				<td>{{ report.reason }}</td>
 | 
			
		||||
				<td>{{ report.created_time }}</td>
 | 
			
		||||
				<td style="width: 15%">
 | 
			
		||||
					<form method="post">
 | 
			
		||||
						{{ report_action.csrf_token }}
 | 
			
		||||
						{{ report_action.action }}
 | 
			
		||||
						{{ report_action.torrent(value=report.torrent.id) }}
 | 
			
		||||
						{{ report_action.report(value=report.id) }}
 | 
			
		||||
						<button type="submit" class="btn btn-primary pull-right">Review</button>
 | 
			
		||||
					</form>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			{% endfor %}
 | 
			
		||||
			</tbody>
 | 
			
		||||
		</table>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class=pagination>
 | 
			
		||||
		{% from "bootstrap/pagination.html" import render_pagination %}
 | 
			
		||||
		{{ render_pagination(reports) }}
 | 
			
		||||
	</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										0
									
								
								nyaa/templates/upload.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								nyaa/templates/upload.html
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							| 
						 | 
				
			
			@ -71,8 +71,12 @@
 | 
			
		|||
			<div class="col-md-5"><kbd>{{ torrent.info_hash_as_hex }}</kbd></div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="panel-footer">
 | 
			
		||||
 | 
			
		||||
	<div class="panel-footer clearfix">
 | 
			
		||||
		{% if torrent.has_torrent %}<a href="{{ url_for('download_torrent', torrent_id=torrent.id )}}"><i class="fa fa-download fa-fw"></i>Download Torrent</a> or {% endif %}<a href="{{ torrent.magnet_uri }}" class="card-footer-item"><i class="fa fa-magnet fa-fw"></i>Magnet</a>
 | 
			
		||||
		<button type="button" class="btn btn-danger pull-right" data-toggle="modal" data-target="#reportModal">
 | 
			
		||||
			Report
 | 
			
		||||
		</button>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +184,29 @@
 | 
			
		|||
	{% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
	<div class="modal fade" id="reportModal" tabindex="-1" role="dialog" aria-labelledby="reportModalLabel">
 | 
			
		||||
	<div class="modal-dialog" role="document">
 | 
			
		||||
		<div class="modal-content">
 | 
			
		||||
			<div class="modal-header">
 | 
			
		||||
				<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
 | 
			
		||||
						aria-hidden="true">×</span></button>
 | 
			
		||||
				<h4 class="modal-title">Report torrent #{{ torrent.id }}</h4>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="modal-body">
 | 
			
		||||
				<form method="POST" action="{{ request.url }}/submit_report">
 | 
			
		||||
					{{ report_form.csrf_token }}
 | 
			
		||||
					{{ render_field(report_form.reason, class_='form-control', maxlength=255) }}
 | 
			
		||||
					<div style="float: right;">
 | 
			
		||||
						<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
 | 
			
		||||
						<button type="submit" class="btn btn-danger">Report</button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</form>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="modal-footer" style="border-top: none;">
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
	var target = document.getElementById('torrent-description');
 | 
			
		||||
	var text = target.innerHTML;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,4 +216,4 @@
 | 
			
		|||
	target.innerHTML = writer.render(parsed);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue