1
0
Fork 0
mirror of https://gitlab.com/SIGBUS/nyaa.git synced 2024-12-22 20:00:01 +00:00
This commit is contained in:
nyaadev 2017-05-19 14:36:33 +02:00
parent e554f9ae97
commit 2a1f8fab87
5 changed files with 43 additions and 36 deletions

View file

@ -9,12 +9,12 @@ from nyaa import torrents
import functools import functools
import json import json
import os.path import os.path
#from orderedset import OrderedSet
#from werkzeug import secure_filename
api_blueprint = flask.Blueprint('api', __name__) api_blueprint = flask.Blueprint('api', __name__)
# #################################### API HELPERS #################################### # #################################### API HELPERS ####################################
def basic_auth_user(f): def basic_auth_user(f):
''' A decorator that will try to validate the user into g.user from basic auth. ''' A decorator that will try to validate the user into g.user from basic auth.
Note: this does not set user to None on failure, so users can also authorize Note: this does not set user to None on failure, so users can also authorize
@ -30,16 +30,18 @@ def basic_auth_user(f):
return f(*args, **kwargs) return f(*args, **kwargs)
return decorator return decorator
def api_require_user(f): def api_require_user(f):
''' Returns an error message if flask.g.user is None. ''' Returns an error message if flask.g.user is None.
Remember to put after basic_auth_user. ''' Remember to put after basic_auth_user. '''
@functools.wraps(f) @functools.wraps(f)
def decorator(*args, **kwargs): def decorator(*args, **kwargs):
if flask.g.user is None: if flask.g.user is None:
return flask.jsonify({'errors':['Bad authorization']}), 403 return flask.jsonify({'errors': ['Bad authorization']}), 403
return f(*args, **kwargs) return f(*args, **kwargs)
return decorator return decorator
def validate_user(upload_request): def validate_user(upload_request):
auth_info = None auth_info = None
try: try:
@ -55,7 +57,8 @@ def validate_user(upload_request):
if not user: if not user:
user = models.User.by_email(username) user = models.User.by_email(username)
if (not user or password != user.password_hash or user.status == models.UserStatusType.INACTIVE): if not user or password != user.password_hash or \
user.status == models.UserStatusType.INACTIVE:
return False, None, None return False, None, None
return True, user, None return True, user, None
@ -85,23 +88,21 @@ def api_upload(upload_request, user):
form_info_as_dict = [] form_info_as_dict = []
for k, v in form_info.items(): for k, v in form_info.items():
if k in ['is_anonymous', 'is_hidden', 'is_remake', 'is_complete']: if k in ['is_anonymous', 'is_hidden', 'is_remake', 'is_complete']:
if v == True: if v:
form_info_as_dict.append((k, v)) form_info_as_dict.append((k, v))
else: else:
form_info_as_dict.append((k, v)) form_info_as_dict.append((k, v))
form_info = ImmutableMultiDict(form_info_as_dict) form_info = ImmutableMultiDict(form_info_as_dict)
# print(repr(form_info))
except Exception as e: except Exception as e:
return flask.make_response(flask.jsonify({'Failure': ['Invalid data. See HELP in api_uploader.py']}), 400) return flask.make_response(flask.jsonify(
{'Failure': ['Invalid data. See HELP in api_uploader.py']}), 400)
try: try:
torrent_file = upload_request.files['torrent_file'] torrent_file = upload_request.files['torrent_file']
torrent_file = ImmutableMultiDict([('torrent_file', torrent_file)]) torrent_file = ImmutableMultiDict([('torrent_file', torrent_file)])
# print(repr(torrent_file))
except Exception as e: except Exception as e:
return flask.make_response(flask.jsonify({'Failure': ['No torrent file was attached.']}), 400) return flask.make_response(flask.jsonify(
{'Failure': ['No torrent file was attached.']}), 400)
form = forms.UploadForm(CombinedMultiDict((torrent_file, form_info))) form = forms.UploadForm(CombinedMultiDict((torrent_file, form_info)))
form.category.choices = _create_upload_category_choices() form.category.choices = _create_upload_category_choices()
@ -111,28 +112,27 @@ def api_upload(upload_request, user):
return flask.make_response(flask.jsonify({'Success': int('{0}'.format(torrent.id))}), 200) return flask.make_response(flask.jsonify({'Success': int('{0}'.format(torrent.id))}), 200)
else: else:
# print(form.errors)
return_error_messages = [] return_error_messages = []
for error_name, error_messages in form.errors.items(): for error_name, error_messages in form.errors.items():
# print(error_messages)
return_error_messages.extend(error_messages) return_error_messages.extend(error_messages)
return flask.make_response(flask.jsonify({'Failure': return_error_messages}), 400) return flask.make_response(flask.jsonify({'Failure': return_error_messages}), 400)
# V2 below # V2 below
# Map UploadForm fields to API keys # Map UploadForm fields to API keys
UPLOAD_API_FORM_KEYMAP = { UPLOAD_API_FORM_KEYMAP = {
'torrent_file' : 'torrent', 'torrent_file': 'torrent',
'display_name' : 'name', 'display_name': 'name',
'is_anonymous' : 'anonymous', 'is_anonymous': 'anonymous',
'is_hidden' : 'hidden', 'is_hidden': 'hidden',
'is_complete' : 'complete', 'is_complete': 'complete',
'is_remake' : 'remake' 'is_remake': 'remake'
} }
UPLOAD_API_FORM_KEYMAP_REVERSE = {v:k for k,v in UPLOAD_API_FORM_KEYMAP.items()} UPLOAD_API_FORM_KEYMAP_REVERSE = {v: k for k, v in UPLOAD_API_FORM_KEYMAP.items()}
UPLOAD_API_KEYS = [ UPLOAD_API_KEYS = [
'name', 'name',
'category', 'category',
@ -144,17 +144,18 @@ UPLOAD_API_KEYS = [
'description' 'description'
] ]
@api_blueprint.route('/v2/upload', methods=['POST']) @api_blueprint.route('/v2/upload', methods=['POST'])
@basic_auth_user @basic_auth_user
@api_require_user @api_require_user
def v2_api_upload(): def v2_api_upload():
mapped_dict = { mapped_dict = {
'torrent_file' : flask.request.files.get('torrent') 'torrent_file': flask.request.files.get('torrent')
} }
request_data_field = flask.request.form.get('torrent_data') request_data_field = flask.request.form.get('torrent_data')
if request_data_field is None: if request_data_field is None:
return flask.jsonify({'errors' : ['missing torrent_data field']}), 400 return flask.jsonify({'errors': ['missing torrent_data field']}), 400
request_data = json.loads(request_data_field) request_data = json.loads(request_data_field)
# Map api keys to upload form fields # Map api keys to upload form fields
@ -171,15 +172,15 @@ def v2_api_upload():
# Create a response dict with relevant data # Create a response dict with relevant data
torrent_metadata = { torrent_metadata = {
'url' : flask.url_for('view_torrent', torrent_id=torrent.id, _external=True), 'url': flask.url_for('view_torrent', torrent_id=torrent.id, _external=True),
'id' : torrent.id, 'id': torrent.id,
'name' : torrent.display_name, 'name': torrent.display_name,
'hash' : torrent.info_hash.hex(), 'hash': torrent.info_hash.hex(),
'magnet' : torrent.magnet_uri 'magnet': torrent.magnet_uri
} }
return flask.jsonify(torrent_metadata) return flask.jsonify(torrent_metadata)
else: else:
# Map errors back from form fields into the api keys # 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() } 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 return flask.jsonify({'errors': mapped_errors}), 400

View file

@ -71,7 +71,8 @@ def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
torrent.trusted = (uploading_user.level >= torrent.trusted = (uploading_user.level >=
models.UserLevelType.TRUSTED) if uploading_user else False models.UserLevelType.TRUSTED) if uploading_user else False
# Set category ids # Set category ids
torrent.main_category_id, torrent.sub_category_id = upload_form.category.parsed_data.get_category_ids() torrent.main_category_id, torrent.sub_category_id = \
upload_form.category.parsed_data.get_category_ids()
# To simplify parsing the filelist, turn single-file torrent into a list # To simplify parsing the filelist, turn single-file torrent into a list
torrent_filelist = info_dict.get('files') torrent_filelist = info_dict.get('files')

View file

@ -7,7 +7,8 @@ import re
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired from flask_wtf.file import FileField, FileRequired
from wtforms import StringField, PasswordField, BooleanField, TextAreaField, SelectField from wtforms import StringField, PasswordField, BooleanField, TextAreaField, SelectField
from wtforms.validators import DataRequired, Optional, Email, Length, EqualTo, ValidationError, Regexp from wtforms.validators import DataRequired, Optional, Email, Length, EqualTo, ValidationError
from wtforms.validators import Regexp
# For DisabledSelectField # For DisabledSelectField
from wtforms.widgets import Select as SelectWidget from wtforms.widgets import Select as SelectWidget

View file

@ -294,7 +294,7 @@ class SubCategory(db.Model):
@classmethod @classmethod
def by_category_ids(cls, main_cat_id, sub_cat_id): def by_category_ids(cls, main_cat_id, sub_cat_id):
return cls.query.get( (sub_cat_id, main_cat_id) ) return cls.query.get((sub_cat_id, main_cat_id))
class UserLevelType(IntEnum): class UserLevelType(IntEnum):

View file

@ -116,6 +116,7 @@ def get_utc_timestamp(datetime_str):
def get_display_time(datetime_str): def get_display_time(datetime_str):
return datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d %H:%M') return datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d %H:%M')
@utils.cached_function @utils.cached_function
def get_category_id_map(): def get_category_id_map():
''' Reads database for categories and turns them into a dict with ''' Reads database for categories and turns them into a dict with
@ -131,8 +132,10 @@ def get_category_id_map():
# Routes start here # # Routes start here #
app.register_blueprint(api_handler.api_blueprint, url_prefix='/api') app.register_blueprint(api_handler.api_blueprint, url_prefix='/api')
@app.route('/rss', defaults={'rss': True}) @app.route('/rss', defaults={'rss': True})
@app.route('/', defaults={'rss': False}) @app.route('/', defaults={'rss': False})
def home(rss): def home(rss):
@ -501,7 +504,8 @@ def profile():
username = _user.username username = _user.username
current_email = _user.email current_email = _user.email
return flask.render_template('profile.html', form=form, name=username, email=current_email, level=level) return flask.render_template('profile.html', form=form, name=username, email=current_email,
level=level)
@app.route('/user/activate/<payload>') @app.route('/user/activate/<payload>')
@ -536,15 +540,15 @@ def _create_upload_category_choices():
is_main_cat = key.endswith('_0') is_main_cat = key.endswith('_0')
cat_name = is_main_cat and cat_names[0] or (' - ' + cat_names[1]) cat_name = is_main_cat and cat_names[0] or (' - ' + cat_names[1])
choices.append( (key, cat_name, is_main_cat) ) choices.append((key, cat_name, is_main_cat))
return choices return choices
@app.route('/upload', methods=['GET', 'POST']) @app.route('/upload', methods=['GET', 'POST'])
def upload(): def upload():
form = forms.UploadForm(CombinedMultiDict((flask.request.files, flask.request.form))) form = forms.UploadForm(CombinedMultiDict((flask.request.files, flask.request.form)))
#print('{0} - {1}'.format(flask.request.files, flask.request.form))
form.category.choices = _create_upload_category_choices() form.category.choices = _create_upload_category_choices()
if flask.request.method == 'POST' and form.validate(): if flask.request.method == 'POST' and form.validate():
torrent = backend.handle_torrent_upload(form, flask.g.user) torrent = backend.handle_torrent_upload(form, flask.g.user)