コード例 #1
0
ファイル: torrents.py プロジェクト: zzdespair/nyaa
def upload():
    upload_form = forms.UploadForm(CombinedMultiDict((flask.request.files, flask.request.form)))
    upload_form.category.choices = _create_upload_category_choices()

    show_ratelimit = False
    next_upload_time = None
    ratelimit_count = 0

    # Anonymous uploaders and non-trusted uploaders

    no_or_new_account = (not flask.g.user
                         or (flask.g.user.age < app.config['RATELIMIT_ACCOUNT_AGE']
                             and not flask.g.user.is_trusted))

    if app.config['RATELIMIT_UPLOADS'] and no_or_new_account:
        now, ratelimit_count, next_upload_time = backend.check_uploader_ratelimit(flask.g.user)
        show_ratelimit = ratelimit_count >= app.config['MAX_UPLOAD_BURST']
        next_upload_time = next_upload_time if next_upload_time > now else None

    if flask.request.method == 'POST' and upload_form.validate():
        try:
            torrent = backend.handle_torrent_upload(upload_form, flask.g.user)

            return flask.redirect(flask.url_for('torrents.view', torrent_id=torrent.id))
        except backend.TorrentExtraValidationException:
            pass

    # If we get here with a POST, it means the form data was invalid: return a non-okay status
    status_code = 400 if flask.request.method == 'POST' else 200
    return flask.render_template('upload.html',
                                 upload_form=upload_form,
                                 show_ratelimit=show_ratelimit,
                                 ratelimit_count=ratelimit_count,
                                 next_upload_time=next_upload_time), status_code
コード例 #2
0
def v2_api_upload():
    mapped_dict = {'torrent_file': flask.request.files.get('torrent')}

    request_data_field = flask.request.form.get('torrent_data')
    if request_data_field is None:
        return flask.jsonify({'errors': ['missing torrent_data field']}), 400

    try:
        request_data = json.loads(request_data_field)
    except json.decoder.JSONDecodeError:
        return flask.jsonify(
            {'errors': ['unable to parse valid JSON in torrent_data']}), 400

    # Map api keys to upload form fields
    for key, default in UPLOAD_API_DEFAULTS.items():
        mapped_key = UPLOAD_API_FORM_KEYMAP_REVERSE.get(key, key)
        value = request_data.get(key, default)
        mapped_dict[mapped_key] = value if value is not None else default

    # Flask-WTF (very helpfully!!) automatically grabs the request form, so force a None formdata
    upload_form = forms.UploadForm(None,
                                   data=mapped_dict,
                                   meta={'csrf': False})
    upload_form.category.choices = _create_upload_category_choices()

    if upload_form.validate():
        try:
            torrent = backend.handle_torrent_upload(upload_form, flask.g.user)

            # Create a response dict with relevant data
            torrent_metadata = {
                'url':
                flask.url_for('torrents.view',
                              torrent_id=torrent.id,
                              _external=True),
                'id':
                torrent.id,
                'name':
                torrent.display_name,
                'hash':
                torrent.info_hash.hex(),
                'magnet':
                torrent.magnet_uri
            }

            return flask.jsonify(torrent_metadata)
        except backend.TorrentExtraValidationException:
            pass

    # Map errors back from form fields into the api keys
    mapped_errors = {
        UPLOAD_API_FORM_KEYMAP.get(k, k): v
        for k, v in upload_form.errors.items()
    }
    return flask.jsonify({'errors': mapped_errors}), 400
コード例 #3
0
def upload():
    form = forms.UploadForm(CombinedMultiDict((flask.request.files, flask.request.form)))
    form.category.choices = _create_upload_category_choices()
    if flask.request.method == 'POST' and form.validate():
        torrent = backend.handle_torrent_upload(form, flask.g.user)

        return flask.redirect('/view/' + str(torrent.id))
    else:
        # If we get here with a POST, it means the form data was invalid: return a non-okay status
        status_code = 400 if flask.request.method == 'POST' else 200
        return flask.render_template('upload.html', form=form, user=flask.g.user), status_code
コード例 #4
0
def upload():
    upload_form = forms.UploadForm(CombinedMultiDict((flask.request.files, flask.request.form)))
    upload_form.category.choices = _create_upload_category_choices()

    if flask.request.method == 'POST' and upload_form.validate():
        try:
            torrent = backend.handle_torrent_upload(upload_form, flask.g.user)

            return flask.redirect(flask.url_for('torrents.view', torrent_id=torrent.id))
        except backend.TorrentExtraValidationException:
            pass

    # If we get here with a POST, it means the form data was invalid: return a non-okay status
    status_code = 400 if flask.request.method == 'POST' else 200
    return flask.render_template('upload.html', upload_form=upload_form), status_code
コード例 #5
0
ファイル: api_handler.py プロジェクト: cybort/nyaa-1
def api_upload(upload_request, user):
    form_info = None
    try:
        form_info = json.loads(
            upload_request.files['torrent_info'].read().decode('utf-8'))

        form_info_as_dict = []
        for k, v in form_info.items():
            if k in ['is_anonymous', 'is_hidden', 'is_remake', 'is_complete']:
                if v == True:
                    form_info_as_dict.append((k, v))
            else:
                form_info_as_dict.append((k, v))
        form_info = ImmutableMultiDict(form_info_as_dict)

        # print(repr(form_info))
    except Exception as e:
        return flask.make_response(
            flask.jsonify(
                {'Failure': ['Invalid data. See HELP in api_uploader.py']}),
            400)

    try:
        torrent_file = upload_request.files['torrent_file']
        torrent_file = ImmutableMultiDict([('torrent_file', torrent_file)])

        # print(repr(torrent_file))
    except Exception as e:
        pass

    form = forms.UploadForm(CombinedMultiDict((torrent_file, form_info)))
    form.category.choices = _create_upload_category_choices()

    if upload_request.method == 'POST' and form.validate():
        torrent = backend.handle_torrent_upload(form, user, True)

        return flask.make_response(
            flask.jsonify({'Success': int('{0}'.format(torrent.id))}), 200)
    else:
        # print(form.errors)
        return_error_messages = []
        for error_name, error_messages in form.errors.items():
            # print(error_messages)
            return_error_messages.extend(error_messages)

        return flask.make_response(
            flask.jsonify({'Failure': return_error_messages}), 400)
コード例 #6
0
ファイル: api_handler.py プロジェクト: cybort/nyaa-1
def v2_api_upload():
    mapped_dict = {'torrent_file': flask.request.files.get('torrent')}

    request_data_field = flask.request.form.get('torrent_data')
    if request_data_field is None:
        return flask.jsonify({'errors': ['missing torrent_data field']}), 400
    request_data = json.loads(request_data_field)

    # Map api keys to upload form fields
    for key in UPLOAD_API_KEYS:
        mapped_key = UPLOAD_API_FORM_KEYMAP_REVERSE.get(key, key)
        mapped_dict[mapped_key] = request_data.get(key)

    # Flask-WTF (very helpfully!!) automatically grabs the request form, so force a None formdata
    upload_form = forms.UploadForm(None, data=mapped_dict)
    upload_form.category.choices = _create_upload_category_choices()

    if upload_form.validate():
        torrent = backend.handle_torrent_upload(upload_form, flask.g.user)

        # Create a response dict with relevant data
        torrent_metadata = {
            'url':
            flask.url_for('view_torrent',
                          torrent_id=torrent.id,
                          _external=True),
            'id':
            torrent.id,
            'name':
            torrent.display_name,
            'hash':
            torrent.info_hash.hex(),
            'magnet':
            torrent.magnet_uri
        }

        return flask.jsonify(torrent_metadata)
    else:
        # Map errors back from form fields into the api keys
        mapped_errors = {
            UPLOAD_API_FORM_KEYMAP.get(k, k): v
            for k, v in upload_form.errors.items()
        }
        return flask.jsonify({'errors': mapped_errors}), 400
コード例 #7
0
def upload():
    current_user = flask.g.user
    form = forms.UploadForm(
        CombinedMultiDict((flask.request.files, flask.request.form)))
    form.category.choices = _create_upload_category_choices()
    if flask.request.method == 'POST' and form.validate():
        torrent_data = form.torrent_file.parsed_data

        # The torrent has been  validated and is safe to access with ['foo'] etc - all relevant
        # keys and values have been checked for (see UploadForm in forms.py for details)
        info_dict = torrent_data.torrent_dict['info']

        changed_to_utf8 = _replace_utf8_values(torrent_data.torrent_dict)

        # Use uploader-given name or grab it from the torrent
        display_name = form.display_name.data.strip(
        ) or info_dict['name'].decode('utf8').strip()
        information = (form.information.data or '').strip()
        description = (form.description.data or '').strip()

        torrent_filesize = info_dict.get('length') or sum(
            f['length'] for f in info_dict.get('files'))

        # In case no encoding, assume UTF-8.
        torrent_encoding = torrent_data.torrent_dict.get(
            'encoding', b'utf-8').decode('utf-8')

        torrent = models.Torrent(info_hash=torrent_data.info_hash,
                                 display_name=display_name,
                                 torrent_name=torrent_data.filename,
                                 information=information,
                                 description=description,
                                 encoding=torrent_encoding,
                                 filesize=torrent_filesize,
                                 user=current_user)

        # Store bencoded info_dict
        torrent.info = models.TorrentInfo(
            info_dict=torrent_data.bencoded_info_dict)
        torrent.stats = models.Statistic()
        torrent.has_torrent = True

        # Fields with default value will be None before first commit, so set .flags
        torrent.flags = 0

        torrent.anonymous = form.is_anonymous.data if current_user else True
        torrent.hidden = form.is_hidden.data
        torrent.remake = form.is_remake.data
        torrent.complete = form.is_complete.data
        # Copy trusted status from user if possible
        torrent.trusted = (current_user.level >= models.UserLevelType.TRUSTED
                           ) if current_user else False

        # Set category ids
        torrent.main_category_id, torrent.sub_category_id = form.category.parsed_data.get_category_ids(
        )
        # print('Main cat id: {0}, Sub cat id: {1}'.format(
        #    torrent.main_category_id, torrent.sub_category_id))

        # To simplify parsing the filelist, turn single-file torrent into a list
        torrent_filelist = info_dict.get('files')

        used_path_encoding = changed_to_utf8 and 'utf-8' or torrent_encoding

        parsed_file_tree = dict()
        if not torrent_filelist:
            # If single-file, the root will be the file-tree (no directory)
            file_tree_root = parsed_file_tree
            torrent_filelist = [{
                'length': torrent_filesize,
                'path': [info_dict['name']]
            }]
        else:
            # If multi-file, use the directory name as root for files
            file_tree_root = parsed_file_tree.setdefault(
                info_dict['name'].decode(used_path_encoding), {})

        # Parse file dicts into a tree
        for file_dict in torrent_filelist:
            # Decode path parts from utf8-bytes
            path_parts = [
                path_part.decode(used_path_encoding)
                for path_part in file_dict['path']
            ]

            filename = path_parts.pop()
            current_directory = file_tree_root

            for directory in path_parts:
                current_directory = current_directory.setdefault(directory, {})

            current_directory[filename] = file_dict['length']

        parsed_file_tree = utils.sorted_pathdict(parsed_file_tree)

        json_bytes = json.dumps(parsed_file_tree,
                                separators=(',', ':')).encode('utf8')
        torrent.filelist = models.TorrentFilelist(filelist_blob=json_bytes)

        db.session.add(torrent)
        db.session.flush()

        # Store the users trackers
        trackers = OrderedSet()
        announce = torrent_data.torrent_dict.get('announce',
                                                 b'').decode('ascii')
        if announce:
            trackers.add(announce)

        # List of lists with single item
        announce_list = torrent_data.torrent_dict.get('announce-list', [])
        for announce in announce_list:
            trackers.add(announce[0].decode('ascii'))

        # Remove our trackers, maybe? TODO ?

        # Search for/Add trackers in DB
        db_trackers = OrderedSet()
        for announce in trackers:
            tracker = models.Trackers.by_uri(announce)

            # Insert new tracker if not found
            if not tracker:
                tracker = models.Trackers(uri=announce)
                db.session.add(tracker)

            db_trackers.add(tracker)

        db.session.flush()

        # Store tracker refs in DB
        for order, tracker in enumerate(db_trackers):
            torrent_tracker = models.TorrentTrackers(torrent_id=torrent.id,
                                                     tracker_id=tracker.id,
                                                     order=order)
            db.session.add(torrent_tracker)

        db.session.commit()

        # Store the actual torrent file as well
        torrent_file = form.torrent_file.data
        if app.config.get('BACKUP_TORRENT_FOLDER'):
            torrent_file.seek(0, 0)

            torrent_dir = app.config['BACKUP_TORRENT_FOLDER']
            if not os.path.exists(torrent_dir):
                os.makedirs(torrent_dir)

            torrent_path = os.path.join(
                torrent_dir,
                '{}.{}'.format(torrent.id,
                               secure_filename(torrent_file.filename)))
            torrent_file.save(torrent_path)
        torrent_file.close()

        return flask.redirect('/view/' + str(torrent.id))
    else:
        # If we get here with a POST, it means the form data was invalid: return a non-okay status
        status_code = 400 if flask.request.method == 'POST' else 200
        return flask.render_template('upload.html',
                                     form=form,
                                     user=flask.g.user), status_code