added endpoint to clean file and return it directly for automated clients

This commit is contained in:
Jan Friedli 2020-08-21 09:09:19 +02:00
parent 5b9bd99eb7
commit 6684517514
No known key found for this signature in database
GPG Key ID: F945FA2FCA30549D
3 changed files with 137 additions and 3 deletions

View File

@ -0,0 +1,41 @@
---
tags:
- "Metadata removal cleaning in one request (automated clients)"
summary: 'Upload a single file which will be cleaned from metadata and returned directly'
requestBody:
description: "The file that will be cleaned from metadata and the cleaned file is returned directly"
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
responses:
'200':
description: "The cleaned file"
content:
"*/*":
schema:
type: string
format: binary
400:
description: "Invalid input"
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
415:
description: "Unsupported file type"
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
500:
description: "Unable to clean the file"
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'

View File

@ -84,6 +84,38 @@ class APIDownload(Resource):
return send_from_directory(current_app.config['UPLOAD_FOLDER'], filepath, as_attachment=True) return send_from_directory(current_app.config['UPLOAD_FOLDER'], filepath, as_attachment=True)
class APIClean(Resource):
@swag_from('./oas/remove_metadata.yml')
def post(self):
if 'file' not in request.files:
abort(400, message='No file part')
uploaded_file = request.files['file']
if not uploaded_file.filename:
abort(400, message='No selected `file`')
try:
filename, filepath = utils.save_file(uploaded_file, current_app.config['UPLOAD_FOLDER'])
except ValueError:
abort(400, message='Invalid Filename')
parser, mime = utils.get_file_parser(filepath)
if parser is None:
abort(415, message='The type %s is not supported' % mime)
if parser.remove_all() is not True:
abort(500, message='Unable to clean %s' % mime)
_, _, _, output_filename = utils.cleanup(parser, filepath, current_app.config['UPLOAD_FOLDER'])
@after_this_request
def remove_file(response):
os.remove(os.path.join(current_app.config['UPLOAD_FOLDER'], output_filename))
return response
return send_from_directory(current_app.config['UPLOAD_FOLDER'], output_filename, as_attachment=True)
class APIBulkDownloadCreator(Resource): class APIBulkDownloadCreator(Resource):
schema = { schema = {
'download_list': { 'download_list': {
@ -168,6 +200,10 @@ api.add_resource(
APIDownload, APIDownload,
'/download/<string:key>/<string:secret>/<string:filename>' '/download/<string:key>/<string:secret>/<string:filename>'
) )
api.add_resource(
APIClean,
'/remove_metadata'
)
api.add_resource( api.add_resource(
APIBulkDownloadCreator, APIBulkDownloadCreator,
'/download/bulk' '/download/bulk'

View File

@ -1,13 +1,15 @@
import unittest
import tempfile
import json import json
import os import os
import shutil import shutil
import tempfile
import unittest
import zipfile import zipfile
from six import BytesIO import io
from unittest.mock import patch from unittest.mock import patch
from openapi_spec_validator import validate_spec from openapi_spec_validator import validate_spec
from six import BytesIO
import main import main
@ -433,5 +435,60 @@ class Mat2APITestCase(unittest.TestCase):
spec = self.app.get('apispec_1.json').get_json() spec = self.app.get('apispec_1.json').get_json()
validate_spec(spec) validate_spec(spec)
def test_remove_metadata(self):
r = self.app.post(
'/api/remove_metadata',
data=dict(
file=(io.BytesIO(b""), 'test.txt'),
),
follow_redirects=False
)
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers['Content-Disposition'], 'attachment; filename=test.cleaned.txt')
self.assertEqual(r.headers['Content-Type'], 'text/plain; charset=utf-8')
self.assertEqual(r.data, b'')
def test_remove_metdata_validation(self):
r = self.app.post(
'/api/remove_metadata',
data=dict(
fileNotExisting=(io.BytesIO(b""), 'test.random'),
),
follow_redirects=False
)
self.assertEqual(r.get_json()['message'], 'No file part')
self.assertEqual(r.status_code, 400)
r = self.app.post(
'/api/remove_metadata',
data=dict(
file=(io.BytesIO(b""), ''),
),
follow_redirects=False
)
self.assertEqual(r.get_json()['message'], 'No selected `file`')
self.assertEqual(r.status_code, 400)
r = self.app.post(
'/api/remove_metadata',
data=dict(
file=(io.BytesIO(b""), '../../'),
),
follow_redirects=False
)
self.assertEqual(r.get_json()['message'], 'Invalid Filename')
self.assertEqual(r.status_code, 400)
r = self.app.post(
'/api/remove_metadata',
data=dict(
file=(io.BytesIO(b""), 'test.random'),
),
follow_redirects=False
)
self.assertEqual(r.get_json()['message'], 'The type None is not supported')
self.assertEqual(r.status_code, 415)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()