mirror of
https://0xacab.org/jvoisin/mat2-web.git
synced 2025-05-12 03:05:19 -04:00
upgrade to oas 3
This commit is contained in:
parent
42f9ede4bf
commit
5d1e6b3235
10 changed files with 178 additions and 134 deletions
|
@ -38,7 +38,7 @@ tests:debian:
|
||||||
- apt-get -qqy update
|
- apt-get -qqy update
|
||||||
- apt-get -qqy install --no-install-recommends mat2 python3-flask python3-coverage python3-pip python3-setuptools
|
- apt-get -qqy install --no-install-recommends mat2 python3-flask python3-coverage python3-pip python3-setuptools
|
||||||
- pip3 install wheel
|
- pip3 install wheel
|
||||||
- pip3 install -r requirements.txt
|
- pip3 install -r requirements.txt -r requirements-test.txt
|
||||||
- python3-coverage run --branch --include main.py,matweb/*.py -m unittest discover -s test
|
- python3-coverage run --branch --include main.py,matweb/*.py -m unittest discover -s test
|
||||||
- python3-coverage report -m
|
- python3-coverage report -m
|
||||||
|
|
||||||
|
|
25
main.py
25
main.py
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import jinja2
|
import jinja2
|
||||||
|
import yaml
|
||||||
|
|
||||||
from matweb import utils, rest_api, frontend
|
from matweb import utils, rest_api, frontend
|
||||||
from flask import Flask, request
|
from flask import Flask, request
|
||||||
|
@ -30,17 +31,31 @@ def create_app(test_config=None):
|
||||||
app.register_blueprint(rest_api.api_bp)
|
app.register_blueprint(rest_api.api_bp)
|
||||||
app.json_encoder = LazyJSONEncoder
|
app.json_encoder = LazyJSONEncoder
|
||||||
|
|
||||||
|
dirname = os.path.dirname(__file__)
|
||||||
|
with open(os.path.join(dirname, 'matweb/oas/components.yml')) as file:
|
||||||
|
components = yaml.full_load(file)
|
||||||
|
|
||||||
template = dict(
|
template = dict(
|
||||||
schemes=['https', 'http'],
|
servers=[
|
||||||
host=LazyString(lambda: request.host),
|
{
|
||||||
basePath='/',
|
'url': LazyString(lambda: request.host_url),
|
||||||
|
'description': 'References the current running server'
|
||||||
|
}
|
||||||
|
],
|
||||||
info={
|
info={
|
||||||
'title': 'Mat2 Web API',
|
'title': 'Mat2 Web API',
|
||||||
'version': '1',
|
'version': '1',
|
||||||
'description': 'Mat2 Web RESTful API documentation',
|
'description': 'Mat2 Web RESTful API documentation',
|
||||||
}
|
},
|
||||||
|
components=components
|
||||||
)
|
)
|
||||||
Swagger(app, template=template)
|
swagger_config = Swagger.DEFAULT_CONFIG
|
||||||
|
swagger_config['swagger_ui_bundle_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js'
|
||||||
|
swagger_config['swagger_ui_standalone_preset_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-standalone-preset.js'
|
||||||
|
swagger_config['swagger_ui_css'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui.css'
|
||||||
|
swagger_config['openapi'] = "3.0.3"
|
||||||
|
Swagger(app, template=template, config=swagger_config)
|
||||||
|
|
||||||
CORS(app, resources={r"/api/*": {"origins": utils.get_allow_origin_header_value()}})
|
CORS(app, resources={r"/api/*": {"origins": utils.get_allow_origin_header_value()}})
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -6,47 +6,32 @@ description: "This endpoint allows you to bulk download several files
|
||||||
which you uploaded beforehand. Note that the `download_list`
|
which you uploaded beforehand. Note that the `download_list`
|
||||||
MUST contain more than two files. The max length is configurable
|
MUST contain more than two files. The max length is configurable
|
||||||
(default is 10)."
|
(default is 10)."
|
||||||
consumes:
|
requestBody:
|
||||||
- "application/json"
|
|
||||||
produces:
|
|
||||||
- "application/json"
|
|
||||||
parameters:
|
|
||||||
- in: "body"
|
|
||||||
name: "body"
|
|
||||||
description: "The files that will be combined for one single download"
|
description: "The files that will be combined for one single download"
|
||||||
required: true
|
required: true
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/BulkBody'
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/BulkBody'
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: "A new resource to download all files as one archive"
|
description: "A new resource to download all files as one archive"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/UploadResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UploadResponse'
|
||||||
400:
|
400:
|
||||||
description: "Invalid input"
|
description: "Invalid input"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/ErrorAtLeastTwoResponse'
|
||||||
|
- $ref: '#/components/schemas/ErrorResponse'
|
||||||
500:
|
500:
|
||||||
description: "Unable to clean the file"
|
description: "Unable to clean the file"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
definitions:
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
BulkBody:
|
|
||||||
type: "object"
|
|
||||||
properties:
|
|
||||||
download_list:
|
|
||||||
type: "array"
|
|
||||||
description: "An object containing the files you want to create a bulk download for"
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/BulkFile'
|
|
||||||
BulkFile:
|
|
||||||
type: "object"
|
|
||||||
properties:
|
|
||||||
file_name:
|
|
||||||
type: "string"
|
|
||||||
key:
|
|
||||||
type: "string"
|
|
||||||
secret:
|
|
||||||
type: "string"
|
|
68
matweb/oas/components.yml
Normal file
68
matweb/oas/components.yml
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
schemas:
|
||||||
|
BulkBody:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
download_list:
|
||||||
|
type: "array"
|
||||||
|
description: "An object containing the files you want to create a bulk download for"
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/BulkFile'
|
||||||
|
BulkFile:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
file_name:
|
||||||
|
type: "string"
|
||||||
|
key:
|
||||||
|
type: "string"
|
||||||
|
secret:
|
||||||
|
type: "string"
|
||||||
|
ErrorAtLeastTwoResponse:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: "object"
|
||||||
|
description: "A description of the error"
|
||||||
|
properties:
|
||||||
|
download_list:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: "Min length is 2"
|
||||||
|
UploadResponse:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
inactive_after_sec:
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
description: "Defines after how many seconds the download wont be available"
|
||||||
|
output_filename:
|
||||||
|
type: "string"
|
||||||
|
description: "The resulting filename after metadata removal"
|
||||||
|
mime:
|
||||||
|
type: "string"
|
||||||
|
description: "The mime type of the cleaned file"
|
||||||
|
key:
|
||||||
|
type: "string"
|
||||||
|
description: "A key used to guarantee file integrity"
|
||||||
|
secret:
|
||||||
|
type: "string"
|
||||||
|
description: "A secret used to guarantee file integrity"
|
||||||
|
meta:
|
||||||
|
type: "object"
|
||||||
|
description: "An object of the removed metadata where key indicates the metadata type"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
meta_after:
|
||||||
|
type: "object"
|
||||||
|
description: "An object of the remaining metadata where key indicates the metadata type"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
download_link:
|
||||||
|
type: "string"
|
||||||
|
description: "The link to download the cleaned file"
|
||||||
|
ErrorResponse:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: "string"
|
||||||
|
description: "A description of the error"
|
|
@ -2,30 +2,39 @@
|
||||||
tags:
|
tags:
|
||||||
- "File Download"
|
- "File Download"
|
||||||
summary: 'Download a single cleaned file or zip archive containing multiple files'
|
summary: 'Download a single cleaned file or zip archive containing multiple files'
|
||||||
consumes:
|
|
||||||
- "application/json"
|
|
||||||
produces:
|
|
||||||
- "*/*"
|
|
||||||
parameters:
|
parameters:
|
||||||
- name: "key"
|
- name: "key"
|
||||||
in: "path"
|
in: "path"
|
||||||
description: "A key generated for that resource"
|
description: "A key generated for that resource"
|
||||||
required: true
|
required: true
|
||||||
type: "string"
|
schema:
|
||||||
- name: "secret"
|
type: "string"
|
||||||
in: "path"
|
- name: "secret"
|
||||||
description: "A secret generated for that resource"
|
in: "path"
|
||||||
required: true
|
description: "A secret generated for that resource"
|
||||||
type: "string"
|
required: true
|
||||||
- name: "filename"
|
schema:
|
||||||
in: "path"
|
type: "string"
|
||||||
description: "the filename of the cleaned file"
|
- name: "filename"
|
||||||
required: true
|
in: "path"
|
||||||
type: "string"
|
description: "the filename of the cleaned file"
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: ""
|
description: "The cleaned file as attachment so a browser downloads the file directly"
|
||||||
|
content:
|
||||||
|
"*/*":
|
||||||
|
schema:
|
||||||
|
format: binary
|
||||||
|
400:
|
||||||
|
description: "Invalid input"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
404:
|
404:
|
||||||
description: "The filename, key or secret are wrong or the link is too old and the file has been deleted"
|
description: "The filename, key or secret are wrong or the link is too old and the file has been deleted"
|
|
@ -2,16 +2,14 @@
|
||||||
tags:
|
tags:
|
||||||
- "Supported Extensions"
|
- "Supported Extensions"
|
||||||
summary: 'Returns a list of all supported file extensions'
|
summary: 'Returns a list of all supported file extensions'
|
||||||
consumes:
|
|
||||||
- "application/json"
|
|
||||||
produces:
|
|
||||||
- "application/json"
|
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "A list of all supported file extensions"
|
description: "A list of all supported file extensions"
|
||||||
schema:
|
content:
|
||||||
type: "array"
|
application/json:
|
||||||
items:
|
schema:
|
||||||
type: "string"
|
type: "array"
|
||||||
example: ".jpeg"
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: ".jpeg"
|
|
@ -2,79 +2,43 @@
|
||||||
tags:
|
tags:
|
||||||
- "File Upload (Metadata removal)"
|
- "File Upload (Metadata removal)"
|
||||||
summary: 'Upload a single file which will be cleaned from metadata'
|
summary: 'Upload a single file which will be cleaned from metadata'
|
||||||
consumes:
|
requestBody:
|
||||||
- "application/json"
|
|
||||||
produces:
|
|
||||||
- "application/json"
|
|
||||||
parameters:
|
|
||||||
- in: "body"
|
|
||||||
name: "body"
|
|
||||||
description: "The file that will be cleaned from metadata. Note that the file must be base64 encoded"
|
description: "The file that will be cleaned from metadata. Note that the file must be base64 encoded"
|
||||||
required: true
|
required: true
|
||||||
schema:
|
content:
|
||||||
type: "object"
|
application/json:
|
||||||
properties:
|
schema:
|
||||||
file_name:
|
type: "object"
|
||||||
type: "string"
|
properties:
|
||||||
example: 'my_example.jpg'
|
file_name:
|
||||||
file:
|
type: "string"
|
||||||
type: "string"
|
example: 'my_example.jpg'
|
||||||
example: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
|
file:
|
||||||
|
type: "string"
|
||||||
|
example: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
201:
|
201:
|
||||||
description: "An object containing all info about the cleaned file"
|
description: "An object containing all info about the cleaned file"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/UploadResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UploadResponse'
|
||||||
400:
|
400:
|
||||||
description: "Invalid input"
|
description: "Invalid input"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
415:
|
415:
|
||||||
description: "Unsupported file type"
|
description: "Unsupported file type"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
500:
|
500:
|
||||||
description: "Unable to clean the file"
|
description: "Unable to clean the file"
|
||||||
schema:
|
content:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
application/json:
|
||||||
|
schema:
|
||||||
definitions:
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
UploadResponse:
|
|
||||||
type: "object"
|
|
||||||
properties:
|
|
||||||
inactive_after_sec:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
description: "Defines after how many seconds the download wont be available"
|
|
||||||
output_filename:
|
|
||||||
type: "string"
|
|
||||||
description: "The resulting filename after metadata removal"
|
|
||||||
mime:
|
|
||||||
type: "string"
|
|
||||||
description: "The mime type of the cleaned file"
|
|
||||||
key:
|
|
||||||
type: "string"
|
|
||||||
description: "A key used to guarantee file integrity"
|
|
||||||
secret:
|
|
||||||
type: "string"
|
|
||||||
description: "A secret used to guarantee file integrity"
|
|
||||||
meta:
|
|
||||||
type: "object"
|
|
||||||
description: "An object of the removed metadata where key indicates the metadata type"
|
|
||||||
items:
|
|
||||||
type: "string"
|
|
||||||
meta_after:
|
|
||||||
type: "object"
|
|
||||||
description: "An object of the remaining metadata where key indicates the metadata type"
|
|
||||||
items:
|
|
||||||
type: "string"
|
|
||||||
download_link:
|
|
||||||
type: "string"
|
|
||||||
description: "The link to download the cleaned file"
|
|
||||||
ErrorResponse:
|
|
||||||
type: "object"
|
|
||||||
properties:
|
|
||||||
message:
|
|
||||||
type: "string"
|
|
||||||
description: "A description of the error"
|
|
1
requirements-test.txt
Normal file
1
requirements-test.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
openapi-spec-validator==0.2.8
|
|
@ -8,4 +8,4 @@ Flask-Cors==3.0.8
|
||||||
Cerberus==1.3.2
|
Cerberus==1.3.2
|
||||||
Flask-Testing==0.8.0
|
Flask-Testing==0.8.0
|
||||||
blinker==1.4
|
blinker==1.4
|
||||||
flasgger==0.9.4
|
iknl-flasgger==0.9.2.post1
|
|
@ -7,6 +7,7 @@ import zipfile
|
||||||
from six import BytesIO
|
from six import BytesIO
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
from openapi_spec_validator import validate_spec
|
||||||
|
|
||||||
import main
|
import main
|
||||||
|
|
||||||
|
@ -420,6 +421,9 @@ class Mat2APITestCase(unittest.TestCase):
|
||||||
self.assertEqual(400, request.status_code)
|
self.assertEqual(400, request.status_code)
|
||||||
self.assertEqual("Failed decoding file", error_message)
|
self.assertEqual("Failed decoding file", error_message)
|
||||||
|
|
||||||
|
def test_valid_opena_api_spec(self):
|
||||||
|
spec = self.app.get('apispec_1.json').get_json()
|
||||||
|
validate_spec(spec)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue