diff options
Diffstat (limited to 'matweb/rest_api.py')
| -rw-r--r-- | matweb/rest_api.py | 59 |
1 files changed, 33 insertions, 26 deletions
diff --git a/matweb/rest_api.py b/matweb/rest_api.py index 2bf44f0..4910b44 100644 --- a/matweb/rest_api.py +++ b/matweb/rest_api.py | |||
| @@ -5,8 +5,8 @@ import binascii | |||
| 5 | import zipfile | 5 | import zipfile |
| 6 | from uuid import uuid4 | 6 | from uuid import uuid4 |
| 7 | 7 | ||
| 8 | from flask import after_this_request, send_from_directory | 8 | from flask import after_this_request, send_from_directory, Blueprint, current_app |
| 9 | from flask_restful import Resource, reqparse, abort, request, url_for | 9 | from flask_restful import Resource, reqparse, abort, request, url_for, Api |
| 10 | from cerberus import Validator | 10 | from cerberus import Validator |
| 11 | from werkzeug.datastructures import FileStorage | 11 | from werkzeug.datastructures import FileStorage |
| 12 | from flasgger import swag_from | 12 | from flasgger import swag_from |
| @@ -15,14 +15,14 @@ from flasgger import swag_from | |||
| 15 | from matweb import file_removal_scheduler, utils | 15 | from matweb import file_removal_scheduler, utils |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | class APIUpload(Resource): | 18 | api_bp = Blueprint('api_bp', __name__, url_prefix='/api/') |
| 19 | 19 | api = Api(api_bp) | |
| 20 | def __init__(self, **kwargs): | 20 | |
| 21 | self.upload_folder = kwargs['upload_folder'] | ||
| 22 | 21 | ||
| 22 | class APIUpload(Resource): | ||
| 23 | @swag_from('./oas/upload.yml') | 23 | @swag_from('./oas/upload.yml') |
| 24 | def post(self): | 24 | def post(self): |
| 25 | utils.check_upload_folder(self.upload_folder) | 25 | utils.check_upload_folder(current_app.config['UPLOAD_FOLDER']) |
| 26 | req_parser = reqparse.RequestParser() | 26 | req_parser = reqparse.RequestParser() |
| 27 | req_parser.add_argument('file_name', type=str, required=True, help='Post parameter is not specified: file_name') | 27 | req_parser.add_argument('file_name', type=str, required=True, help='Post parameter is not specified: file_name') |
| 28 | req_parser.add_argument('file', type=str, required=True, help='Post parameter is not specified: file') | 28 | req_parser.add_argument('file', type=str, required=True, help='Post parameter is not specified: file') |
| @@ -35,7 +35,7 @@ class APIUpload(Resource): | |||
| 35 | 35 | ||
| 36 | file = FileStorage(stream=io.BytesIO(file_data), filename=args['file_name']) | 36 | file = FileStorage(stream=io.BytesIO(file_data), filename=args['file_name']) |
| 37 | try: | 37 | try: |
| 38 | filename, filepath = utils.save_file(file, self.upload_folder) | 38 | filename, filepath = utils.save_file(file, current_app.config['UPLOAD_FOLDER']) |
| 39 | except ValueError: | 39 | except ValueError: |
| 40 | abort(400, message='Invalid Filename') | 40 | abort(400, message='Invalid Filename') |
| 41 | 41 | ||
| @@ -48,7 +48,7 @@ class APIUpload(Resource): | |||
| 48 | if not parser.remove_all(): | 48 | if not parser.remove_all(): |
| 49 | abort(500, message='Unable to clean %s' % mime) | 49 | abort(500, message='Unable to clean %s' % mime) |
| 50 | 50 | ||
| 51 | key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, self.upload_folder) | 51 | key, secret, meta_after, output_filename = utils.cleanup(parser, filepath, current_app.config['UPLOAD_FOLDER']) |
| 52 | return utils.return_file_created_response( | 52 | return utils.return_file_created_response( |
| 53 | utils.get_file_removal_max_age_sec(), | 53 | utils.get_file_removal_max_age_sec(), |
| 54 | output_filename, | 54 | output_filename, |
| @@ -58,7 +58,7 @@ class APIUpload(Resource): | |||
| 58 | meta, | 58 | meta, |
| 59 | meta_after, | 59 | meta_after, |
| 60 | url_for( | 60 | url_for( |
| 61 | 'apidownload', | 61 | 'api_bp.apidownload', |
| 62 | key=key, | 62 | key=key, |
| 63 | secret=secret, | 63 | secret=secret, |
| 64 | filename=output_filename, | 64 | filename=output_filename, |
| @@ -68,16 +68,12 @@ class APIUpload(Resource): | |||
| 68 | 68 | ||
| 69 | 69 | ||
| 70 | class APIDownload(Resource): | 70 | class APIDownload(Resource): |
| 71 | |||
| 72 | def __init__(self, **kwargs): | ||
| 73 | self.upload_folder = kwargs['upload_folder'] | ||
| 74 | |||
| 75 | @swag_from('./oas/download.yml') | 71 | @swag_from('./oas/download.yml') |
| 76 | def get(self, key: str, secret: str, filename: str): | 72 | def get(self, key: str, secret: str, filename: str): |
| 77 | complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, self.upload_folder) | 73 | complete_path, filepath = utils.is_valid_api_download_file(filename, key, secret, current_app.config['UPLOAD_FOLDER']) |
| 78 | # Make sure the file is NOT deleted on HEAD requests | 74 | # Make sure the file is NOT deleted on HEAD requests |
| 79 | if request.method == 'GET': | 75 | if request.method == 'GET': |
| 80 | file_removal_scheduler.run_file_removal_job(self.upload_folder) | 76 | file_removal_scheduler.run_file_removal_job(current_app.config['UPLOAD_FOLDER']) |
| 81 | 77 | ||
| 82 | @after_this_request | 78 | @after_this_request |
| 83 | def remove_file(response): | 79 | def remove_file(response): |
| @@ -85,14 +81,10 @@ class APIDownload(Resource): | |||
| 85 | os.remove(complete_path) | 81 | os.remove(complete_path) |
| 86 | return response | 82 | return response |
| 87 | 83 | ||
| 88 | return send_from_directory(self.upload_folder, filepath, as_attachment=True) | 84 | return send_from_directory(current_app.config['UPLOAD_FOLDER'], filepath, as_attachment=True) |
| 89 | 85 | ||
| 90 | 86 | ||
| 91 | class APIBulkDownloadCreator(Resource): | 87 | class APIBulkDownloadCreator(Resource): |
| 92 | |||
| 93 | def __init__(self, **kwargs): | ||
| 94 | self.upload_folder = kwargs['upload_folder'] | ||
| 95 | |||
| 96 | schema = { | 88 | schema = { |
| 97 | 'download_list': { | 89 | 'download_list': { |
| 98 | 'type': 'list', | 90 | 'type': 'list', |
| @@ -112,13 +104,13 @@ class APIBulkDownloadCreator(Resource): | |||
| 112 | 104 | ||
| 113 | @swag_from('./oas/bulk.yml') | 105 | @swag_from('./oas/bulk.yml') |
| 114 | def post(self): | 106 | def post(self): |
| 115 | utils.check_upload_folder(self.upload_folder) | 107 | utils.check_upload_folder(current_app.config['UPLOAD_FOLDER']) |
| 116 | data = request.json | 108 | data = request.json |
| 117 | if not self.v.validate(data): | 109 | if not self.v.validate(data): |
| 118 | abort(400, message=self.v.errors) | 110 | abort(400, message=self.v.errors) |
| 119 | # prevent the zip file from being overwritten | 111 | # prevent the zip file from being overwritten |
| 120 | zip_filename = 'files.' + str(uuid4()) + '.zip' | 112 | zip_filename = 'files.' + str(uuid4()) + '.zip' |
| 121 | zip_path = os.path.join(self.upload_folder, zip_filename) | 113 | zip_path = os.path.join(current_app.config['UPLOAD_FOLDER'], zip_filename) |
| 122 | cleaned_files_zip = zipfile.ZipFile(zip_path, 'w') | 114 | cleaned_files_zip = zipfile.ZipFile(zip_path, 'w') |
| 123 | with cleaned_files_zip: | 115 | with cleaned_files_zip: |
| 124 | for file_candidate in data['download_list']: | 116 | for file_candidate in data['download_list']: |
| @@ -126,7 +118,7 @@ class APIBulkDownloadCreator(Resource): | |||
| 126 | file_candidate['file_name'], | 118 | file_candidate['file_name'], |
| 127 | file_candidate['key'], | 119 | file_candidate['key'], |
| 128 | file_candidate['secret'], | 120 | file_candidate['secret'], |
| 129 | self.upload_folder | 121 | current_app.config['UPLOAD_FOLDER'] |
| 130 | ) | 122 | ) |
| 131 | try: | 123 | try: |
| 132 | cleaned_files_zip.write(complete_path) | 124 | cleaned_files_zip.write(complete_path) |
| @@ -142,7 +134,7 @@ class APIBulkDownloadCreator(Resource): | |||
| 142 | parser, mime = utils.get_file_parser(zip_path) | 134 | parser, mime = utils.get_file_parser(zip_path) |
| 143 | if not parser.remove_all(): | 135 | if not parser.remove_all(): |
| 144 | abort(500, message='Unable to clean %s' % mime) | 136 | abort(500, message='Unable to clean %s' % mime) |
| 145 | key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, self.upload_folder) | 137 | key, secret, meta_after, output_filename = utils.cleanup(parser, zip_path, current_app.config['UPLOAD_FOLDER']) |
| 146 | return { | 138 | return { |
| 147 | 'inactive_after_sec': utils.get_file_removal_max_age_sec(), | 139 | 'inactive_after_sec': utils.get_file_removal_max_age_sec(), |
| 148 | 'output_filename': output_filename, | 140 | 'output_filename': output_filename, |
| @@ -151,7 +143,7 @@ class APIBulkDownloadCreator(Resource): | |||
| 151 | 'secret': secret, | 143 | 'secret': secret, |
| 152 | 'meta_after': meta_after, | 144 | 'meta_after': meta_after, |
| 153 | 'download_link': url_for( | 145 | 'download_link': url_for( |
| 154 | 'apidownload', | 146 | 'api_bp.apidownload', |
| 155 | key=key, | 147 | key=key, |
| 156 | secret=secret, | 148 | secret=secret, |
| 157 | filename=output_filename, | 149 | filename=output_filename, |
| @@ -164,3 +156,18 @@ class APISupportedExtensions(Resource): | |||
| 164 | @swag_from('./oas/extension.yml') | 156 | @swag_from('./oas/extension.yml') |
| 165 | def get(self): | 157 | def get(self): |
| 166 | return utils.get_supported_extensions() | 158 | return utils.get_supported_extensions() |
| 159 | |||
| 160 | |||
| 161 | api.add_resource( | ||
| 162 | APIUpload, | ||
| 163 | '/upload' | ||
| 164 | ) | ||
| 165 | api.add_resource( | ||
| 166 | APIDownload, | ||
| 167 | '/download/<string:key>/<string:secret>/<string:filename>' | ||
| 168 | ) | ||
| 169 | api.add_resource( | ||
| 170 | APIBulkDownloadCreator, | ||
| 171 | '/download/bulk' | ||
| 172 | ) | ||
| 173 | api.add_resource(APISupportedExtensions, '/extension') | ||
