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
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
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
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
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)
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
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