Esempio n. 1
0
    def dispatch(self, request, method=''):
        # in case we do something json doesn't like, we always get back valid
        # json-rpc response
        response = self.empty_response()

        try:
            raw_data = extract_raw_data_request(request)

            if request.method == 'GET':
                valid, D = self.validate_get(request, method)
                if not valid:
                    raise InvalidRequestError(
                        'The method you are trying to access is '
                        'not availble by GET requests')
            elif not request.method == 'POST':
                raise RequestPostError
            else:
                try:
                    D = json.loads(raw_data)
                except Exception, e:
                    raise InvalidRequestError(e.message)

            if type(D) is list:
                response = [
                    self.response_dict(request, d, is_batch=True)[0] for d in D
                ]
                status = 200
            else:
                response, status = self.response_dict(request, D)
                if response is None and (not u'id' in D or
                                         D[u'id'] is None):  # a notification
                    response = ''
                    return response, status
Esempio n. 2
0
    def batch_response_obj(self, request, D):
        status = 200
        try:
            responses = [self.response_obj(request, d)[0] for d in D]
            if not responses:
                raise InvalidRequestError('Empty array')
        except Error as e:
            for response in responses:
                response.pop('result', None)
                response['error'] = e.json_rpc_format
        except Exception as e:
            other_error = OtherError(e)
            for response in responses:
                response.pop('result', None)
                response['error'] = other_error.json_rpc_format

        for response in responses:
            if response is None:
                continue  # notification
            # Exactly one of result or error MUST be specified. It's not
            # allowed to specify both or none.
            if 'result' in response:
                response.pop('error', None)

        if not responses:
            response = self.empty_response(version='2.0')
            response['error'] = InvalidRequestError().json_rpc_format
            response.pop('result', None)
            responses = response

        if not all(responses):
            return '', 204  # notification

        return responses, status
Esempio n. 3
0
    def search_movie_id(self, filename):
        name, year = self.parse_movie_name(filename)

        if name is None:
            return None

        params_list = [{
            'query': name,
            'primary_release_year': year
        }, {
            'query': name,
            'year': year
        }]

        resp_json = None
        for params in params_list:
            resp_json = self.search_movie(params)

            if 'total_results' in resp_json.keys() and \
                    resp_json['total_results'] > 0:
                break

        if 'total_results' not in resp_json.keys():
            if 'errors' in resp_json.keys():
                raise InvalidRequestError(message=resp_json['errors'])
            raise InvalidRequestError(message=resp_json.get('status_message'))

        if resp_json['total_results'] < 1:
            return None

        return resp_json['results'][0]['id']
Esempio n. 4
0
def get_item_content_url(item_id: str, item: dict = None) -> str:
    item_doc = item or get_item(item_id)

    if 'folder' in item_doc.keys():
        raise InvalidRequestError(
            message='You cannot get content for a folder')

    if item_doc['size'] > 50 * 1024 * 1024:
        raise InvalidRequestError(message='Large file uses shared link')

    drive = Drive.create_from_id(item_doc['parentReference']['driveId'])
    return drive_api.content_url(drive.token, item_id)
Esempio n. 5
0
    def dispatch(self, request, method=''):
        # in case we do something json doesn't like, we always get back valid
        # json-rpc response
        response = self.empty_response()
        raw_data = extract_raw_data_request(request)

        try:
            if request.method == 'GET':
                valid, D = self.validate_get(request, method)
                if not valid:
                    raise InvalidRequestError(
                        'The method you are trying to access is '
                        'not availble by GET requests')
            elif not request.method == 'POST':
                raise RequestPostError
            else:
                try:
                    D = json.loads(raw_data)
                except Exception as e:
                    raise InvalidRequestError(e.message)

            if type(D) is list:
                response = [(yield from self.response_dict(request,
                                                           d,
                                                           is_batch=True))[0]
                            for d in D]
                status = 200
            else:
                response, status = (yield from self.response_dict(request, D))
                if response is None and (not 'id' in D
                                         or D['id'] is None):  # a notification
                    response = ''
                    return response, status
        except Error as e:
            #got_request_exception.connect(log_exception, current_app._get_current_object())

            response['error'] = e.json_rpc_format
            status = e.status
        except Exception as e:
            # exception missed by others
            #got_request_exception.connect(log_exception, current_app._get_current_object())

            other_error = OtherError(e)
            response['result'] = None
            response['error'] = other_error.json_rpc_format
            status = other_error.status

        # extract id the request
        json_request_id = self.extract_id_request(raw_data)
        response['id'] = json_request_id

        return response, status
Esempio n. 6
0
def get_item_shared_link(item_id: str, item: dict = None) -> Union[str, None]:
    item_doc = item or get_item(item_id)
    if 'folder' in item_doc.keys():
        raise InvalidRequestError(message='You cannot get link for a folder')

    create_link = item_doc.get('create_link')

    if create_link is not None:
        expiration_date_time = create_link.get('expirationDateTime') or ''
        if expiration_date_time < Utils.utc_datetime(
                timedelta=datetime.timedelta(days=1)):
            create_link = None

    if create_link is None:
        return None

    drive_id = item_doc['parentReference']['driveId']
    base_down_url = get_base_down_url(drive_id, item_id)
    web_url = create_link['link']['webUrl']
    share = web_url[web_url.rfind('/') + 1:]
    # download.aspx 加上 '/' 再在后面加任意字符串都行,这里加个文件名方便识别
    direct_link = base_down_url.replace(
        '?share=', '/' + item_doc['name'] + '?share=') + share

    return direct_link
Esempio n. 7
0
    def make_response(self, rv):
        """Converts the return value from a view function to a real
        response object that is an instance of :attr:`response_class`.
        """
        status_or_headers = headers = None
        if isinstance(rv, tuple):
            rv, status_or_headers, headers = rv + (None, ) * (3 - len(rv))

        if rv is None:
            raise ValueError('View function did not return a response')

        if isinstance(status_or_headers, (dict, list)):
            headers, status_or_headers = status_or_headers, None

        D = json.loads(extract_raw_data_request(request))
        if type(D) is list:
            raise InvalidRequestError(
                'JSON-RPC batch with decorator (make_response) not is supported'
            )
        else:
            response_obj = self.empty_response(version=D['jsonrpc'])
            response_obj['id'] = D['id']
            response_obj['result'] = rv
            response_obj.pop('error', None)
            rv = jsonify(response_obj)

        if status_or_headers is not None:
            if isinstance(status_or_headers, string_types):
                rv.status = status_or_headers
            else:
                rv.status_code = status_or_headers
        if headers:
            rv.headers.extend(headers)

        return rv
Esempio n. 8
0
def upload_file(drive_id: str, upload_path: str, file_path: str) -> int:
    """

    :param drive_id:
    :param upload_path: 上传至此目录下,结尾带‘/’
    :param file_path: 本地文件路径
    :return:
    """
    upload_path = upload_path.strip().replace('\\', '/')
    file_path = file_path.strip().replace('\\', '/')

    if not upload_path.endswith('/'):
        upload_path = upload_path + '/'

    if os.path.isfile(file_path) is False:
        raise InvalidRequestError(message='File not found.')

    file_size = os.path.getsize(file_path)
    if file_size <= 0:
        return -1

    _, filename = os.path.split(file_path)
    uid = str(uuid.uuid4())
    upload_info = UploadInfo(uid=uid,
                             drive_id=drive_id,
                             filename=filename,
                             file_path=file_path,
                             upload_path=upload_path,
                             size=file_size,
                             created_date_time=Utils.str_datetime())
    mongodb.upload_info.insert_one(upload_info.json())

    upload_pool.add_task(uid)

    return 0
Esempio n. 9
0
    def dispatch(self, request, method=''):
        # in case we do something json doesn't like, we always get back valid
        # json-rpc response
        response = self.empty_response()
        raw_data = extract_raw_data_request(request)

        try:
            if request.method == 'GET':
                valid, D = self.validate_get(request, method)
                if not valid:
                    raise InvalidRequestError(
                        'The method you are trying to access is '
                        'not availble by GET requests')
            elif not request.method == 'POST':
                raise RequestPostError()
            else:
                try:
                    D = json.loads(raw_data)
                except Exception as e:
                    raise ParseError(
                        getattr(e, 'message',
                                e.args[0] if len(e.args) > 0 else None))

            if type(D) is list:
                return self.batch_response_obj(request, D)

            response, status = self.response_obj(request, D)

            if isinstance(response, Response):
                return response, status

            if response is None and (not 'id' in D
                                     or D['id'] is None):  # a notification
                response = ''
                return response, status
        except Error as e:
            response.pop('result', None)
            response['error'] = e.json_rpc_format
            status = e.status
        except Exception as e:
            other_error = OtherError(e)
            response.pop('result', None)
            response['error'] = other_error.json_rpc_format
            status = other_error.status

        # extract id the request
        if not response.get('id', False):
            json_request_id = self.extract_id_request(raw_data)
            response['id'] = json_request_id

        # If there was an error in detecting the id in the Request object
        # (e.g. Parse error/Invalid Request), it MUST be Null.
        if not response and 'error' in response:
            if response['error']['name'] in ('ParseError',
                                             'InvalidRequestError',
                                             'RequestPostError'):
                response['id'] = None

        return response, status
Esempio n. 10
0
def get_settings(drive_id: str) -> dict:
    doc = mongodb.drive.find_one({'id': drive_id}, {'_id': 0, 'settings': 1})
    if doc is None:
        raise InvalidRequestError(message='Cannot find drive')

    settings = doc.get('settings') or {}
    for k, v in default_settings.items():
        settings[k] = settings.get(k) or v

    return settings
Esempio n. 11
0
def modify_settings(drive_id: str, name: str, value: Union[str, bool,
                                                           int]) -> int:
    if name not in default_settings.keys():
        raise InvalidRequestError(message='Wrong settings name')

    new_value = value
    if name.endswith('_path'):
        # 根目录 '/', 其他目录以'/'开头,结尾不带'/'
        new_value = Utils.path_with_slash(new_value)
    r = mongodb.drive.update_one({'id': drive_id},
                                 {'$set': {
                                     'settings.' + name: new_value
                                 }})
    if r.matched_count == 0:
        return -1
    return 0
Esempio n. 12
0
def get_movie(movie_id: int, append_collection: bool = False) -> dict:
    for item in mongodb.tmdb_movie.aggregate([
        {'$match': {'id': movie_id}},
        {'$lookup': {
            'from': 'tmdb_person',
            'localField': 'directors',
            'foreignField': 'id',
            'as': 'directors'
        }},
        {'$unset': 'directors._id'},
        {'$project': get_movie_projection}
    ]):
        if append_collection and item.get('belongs_to_collection') is not None:
            item['belongs_to_collection'] = get_collection(
                item['belongs_to_collection']['id'])
        return item

    raise InvalidRequestError(message='Invalid movie id')
Esempio n. 13
0
def upload_folder(drive_id: str, upload_path: str, folder_path: str) -> int:
    """
    上传文件夹下的所有文件,不包括子文件夹
    :param drive_id:
    :param upload_path: 上传至此目录下,结尾带‘/’
    :param folder_path: 上传此目录下的文件,结尾带'/'
    :return:
    """
    upload_path = upload_path.strip().replace('\\', '/')
    folder_path = folder_path.strip().replace('\\', '/')

    if not upload_path.endswith('/'):
        upload_path = upload_path + '/'
    if not folder_path.endswith('/'):
        folder_path = folder_path + '/'

    if os.path.isdir(folder_path) is False:
        raise InvalidRequestError(message='Folder not found.')

    _, folder_name = os.path.split(folder_path[:-1])
    for file in sorted(os.listdir(folder_path), key=lambda x: x.lower()):
        file_path = folder_path + file
        if os.path.isfile(file_path) is False:
            continue

        file_size = os.path.getsize(file_path)
        if file_size <= 0:
            continue

        uid = str(uuid.uuid4())
        upload_info = UploadInfo(uid=uid,
                                 drive_id=drive_id,
                                 filename=file,
                                 file_path=file_path,
                                 upload_path=upload_path + folder_name + '/',
                                 size=file_size,
                                 created_date_time=Utils.str_datetime())
        mongodb.upload_info.insert_one(upload_info.json())

        upload_pool.add_task(uid)
    return 0
Esempio n. 14
0
def get_item(item_id: str) -> dict:
    doc = mongodb.item.find_one({'id': item_id}, {'_id': 0})
    if doc is None:
        raise InvalidRequestError(message='Cannot find item')

    return doc
Esempio n. 15
0
    def response_obj(self, request, D, version_hint=JSONRPC_VERSION_DEFAULT):
        version = version_hint
        response = self.empty_response(version=version)
        apply_version = {
            '2.0': self.apply_version_2_0,
            '1.1': self.apply_version_1_1,
            '1.0': self.apply_version_1_0
        }

        try:
            try:
                # determine if an object is iterable?
                iter(D)
            except TypeError as e:
                raise InvalidRequestError(
                    getattr(e, 'message',
                            e.args[0] if len(e.args) > 0 else None))

            # version: validate
            if 'jsonrpc' in D:
                if text_type(D['jsonrpc']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version {0} not supported.'.format(
                            D['jsonrpc']))
                version = request.jsonrpc_version = response[
                    'jsonrpc'] = text_type(D['jsonrpc'])
            elif 'version' in D:
                if text_type(D['version']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version {0} not supported.'.format(
                            D['version']))
                version = request.jsonrpc_version = response[
                    'version'] = text_type(D['version'])
            else:
                version = request.jsonrpc_version = JSONRPC_VERSION_DEFAULT

            # params: An Array or Object, that holds the actual parameter values
            # for the invocation of the procedure. Can be omitted if empty.
            if 'params' not in D or not D['params']:
                D['params'] = []
            if 'method' not in D or 'params' not in D:
                raise InvalidParamsError(
                    'Request requires str:"method" and list:"params"')
            if D['method'] not in self.urls:
                raise MethodNotFoundError('Method not found. Available methods: {0}' \
                    .format('\n'.join(list(self.urls.keys()))))

            method = self.urls[text_type(D['method'])]
            if getattr(method, 'json_validate', False):
                validate_params(method, D)

            if 'id' in D and D['id'] is not None:  # regular request
                response['id'] = D['id']
                if version in ('1.1', '2.0'):
                    response.pop('error', None)
            else:  # notification
                return None, 204

            R = apply_version[version](method, D['params'])

            if 'id' not in D or ('id' in D
                                 and D['id'] is None):  # notification
                return None, 204

            if isinstance(R, Response):
                if R.status_code == 200:
                    return R, R.status_code
                if R.status_code == 401:
                    raise InvalidCredentialsError(R.status)
                raise OtherError(R.status, R.status_code)

            try:
                # New in Flask version 0.10.
                encoder = current_app.json_encoder()
            except AttributeError:
                encoder = json.JSONEncoder()

            # type of `R` should be one of these or...
            if not sum([isinstance(R, e) for e in \
                    string_types + integer_types + \
                    (float, complex, dict, list, tuple, set, frozenset, NoneType, bool)]):
                try:
                    rs = encoder.default(
                        R)  # ...or something this thing supports
                except TypeError as exc:
                    raise TypeError(
                        'Return type not supported, for {0!r}'.format(R))

            response['result'] = R
            status = 200
        except Error as e:
            response['error'] = e.json_rpc_format
            if version in ('1.1', '2.0'):
                response.pop('result', None)
            status = e.status
        except HTTPException as e:
            other_error = OtherError(e)
            response['error'] = other_error.json_rpc_format
            response['error']['code'] = e.code
            if version in ('1.1', '2.0'):
                response.pop('result', None)
            status = e.code
        except Exception as e:
            other_error = OtherError(e)
            response['error'] = other_error.json_rpc_format
            status = other_error.status
            if version in ('1.1', '2.0'):
                response.pop('result', None)

        # Exactly one of result or error MUST be specified. It's not
        # allowed to specify both or none.
        if version in ('1.1', '2.0') and 'result' in response:
            response.pop('error', None)

        return response, status
Esempio n. 16
0
    def response_dict(self, request, D, is_batch=False, version_hint='1.0'):
        version = version_hint
        response = self.empty_response(version=version)
        apply_version = {
            '2.0': lambda f, p: f(**encode_kw(p))
            if type(p) is dict else f(*p),
            '1.1':
            lambda f, p: f(*encode_arg11(p), **encode_kw(encode_kw11(p))),
            '1.0': lambda f, p: f(*p)
        }

        try:
            # params: An Array or Object, that holds the actual parameter values
            # for the invocation of the procedure. Can be omitted if empty.
            if 'params' not in D or not D['params']:
                D['params'] = []
            if 'method' not in D or 'params' not in D:
                raise InvalidParamsError(
                    'Request requires str:"method" and list:"params"')
            if D['method'] not in self.urls:
                raise MethodNotFoundError('Method not found. Available methods: {0}' \
                    .format('\n'.join(list(self.urls.keys()))))

            if 'jsonrpc' in D:
                if text_type(D['jsonrpc']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version {0} not supported.'.format(
                            D['jsonrpc']))
                version = request.jsonrpc_version = response[
                    'jsonrpc'] = text_type(D['jsonrpc'])
            elif 'version' in D:
                if text_type(D['version']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version {0} not supported.'.format(
                            D['version']))
                version = request.jsonrpc_version = response[
                    'version'] = text_type(D['version'])
            else:
                request.jsonrpc_version = '1.0'

            method = self.urls[text_type(D['method'])]
            if getattr(method, 'json_validate', False):
                validate_params(method, D)

            if 'id' in D and D['id'] is not None:  # regular request
                response['id'] = D['id']
                if version in ('1.1', '2.0') and 'error' in response:
                    response.pop('error')
            elif is_batch:  # notification, not ok in a batch format, but happened anyway
                raise InvalidRequestError
            else:  # notification
                return None, 204

            R = apply_version[version](method, D['params'])
            if asyncio.iscoroutine(R):
                R = (yield from R)

            if 'id' not in D or ('id' in D
                                 and D['id'] is None):  # notification
                return None, 204

            encoder = current_app.json_encoder()

            # type of `R` should be one of these or...
            if not sum([isinstance(R, e) for e in \
                    string_types + integer_types + (dict, list, set, NoneType, bool)]):
                try:
                    rs = encoder.default(
                        R)  # ...or something this thing supports
                except TypeError as exc:
                    raise TypeError(
                        "Return type not supported, for {0!r}".format(R))

            response['result'] = R

            status = 200

        except Error as e:
            # exception missed by others
            #got_request_exception.connect(log_exception, current_app._get_current_object())

            response['error'] = e.json_rpc_format
            if version in ('1.1', '2.0') and 'result' in response:
                response.pop('result')
            status = e.status
        except HTTPException as e:
            # exception missed by others
            #got_request_exception.connect(log_exception, current_app._get_current_object())

            other_error = OtherError(e)
            response['error'] = other_error.json_rpc_format
            response['error']['code'] = e.code
            if version in ('1.1', '2.0') and 'result' in response:
                response.pop('result')
            status = e.code
        except Exception as e:
            # exception missed by others
            #got_request_exception.connect(log_exception, current_app._get_current_object())

            other_error = OtherError(e)
            response['error'] = other_error.json_rpc_format
            status = other_error.status
            if version in ('1.1', '2.0') and 'result' in response:
                response.pop('result')

        # Exactly one of result or error MUST be specified. It's not
        # allowed to specify both or none.
        if version in ('1.1', '2.0'
                       ) and 'error' in response and not response['error']:
            response.pop('error')

        return response, status
Esempio n. 17
0
    def response_dict(self, request, D, is_batch=False, version_hint='1.0'):
        version = version_hint
        response = self.empty_response(version=version)
        apply_version = {
            '2.0': lambda f, r, p: f(**encode_kw(p))
            if type(p) is dict else f(*p),
            '1.1':
            lambda f, r, p: f(*encode_arg11(p), **encode_kw(encode_kw11(p))),
            '1.0': lambda f, r, p: f(*p)
        }

        try:
            # params: An Array or Object, that holds the actual parameter values
            # for the invocation of the procedure. Can be omitted if empty.
            if 'params' not in D or not D['params']:
                D['params'] = []
            if 'method' not in D or 'params' not in D:
                raise InvalidParamsError(
                    'Request requires str:"method" and list:"params"')
            if D['method'] not in self.urls:
                raise MethodNotFoundError(
                    'Method not found. Available methods: %s' %
                    ('\n'.join(self.urls.keys())))

            if 'jsonrpc' in D:
                if str(D['jsonrpc']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version %s not supported.' % D['jsonrpc'])
                version = request.jsonrpc_version = response['jsonrpc'] = str(
                    D['jsonrpc'])
            elif 'version' in D:
                if str(D['version']) not in apply_version:
                    raise InvalidRequestError(
                        'JSON-RPC version %s not supported.' % D['version'])
                version = request.jsonrpc_version = response['version'] = str(
                    D['version'])
            else:
                request.jsonrpc_version = '1.0'

            method = self.urls[str(D['method'])]
            if getattr(method, 'json_validate', False):
                validate_params(method, D)

            if 'id' in D and D['id'] is not None:  # regular request
                response['id'] = D['id']
                if version in ('1.1', '2.0') and 'error' in response:
                    response.pop('error')
            elif is_batch:  # notification, not ok in a batch format, but happened anyway
                raise InvalidRequestError
            else:  # notification
                return None, 204

            R = apply_version[version](method, request, D['params'])

            if 'id' not in D or ('id' in D
                                 and D['id'] is None):  # notification
                return None, 204

            encoder = current_app.json_encoder()
            if not sum(
                    map(
                        lambda e: isinstance(
                            R, e),  # type of `R` should be one of these or...
                        (dict, str, unicode, int, long, list, set, NoneType,
                         bool))):
                try:
                    rs = encoder.default(
                        R)  # ...or something this thing supports
                except TypeError, exc:
                    raise TypeError("Return type not supported, for %r" % R)

            response['result'] = R

            status = 200