Skip to content

Commit

Permalink
Merge pull request #284 from plangrid/acsbp-3718
Browse files Browse the repository at this point in the history
ACSBP-3718 Update to use openapi 3.1
  • Loading branch information
auramix authored Aug 1, 2023
2 parents 645940c + 1bc656e commit 03e660c
Show file tree
Hide file tree
Showing 34 changed files with 720 additions and 1,140 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 2.4.0
current_version = 3.0.0
commit = True
tag = True

Expand Down
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ max-line-length = 120
exclude = .git/*, build/*, examples/*, venv/*, setup.py
per-file-ignores =
flask_rebar/__init__.py: F401 flask_rebar/*/__init__.py: F401
extend-ignore = E501
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ Installation
pip install flask-rebar
Replacing static swagger-ui files
-------------

If you'd like to replace swagger-ui's static files (`flask_rebar/swagger_ui/static`) with those of the latest release,
run the following from the root of the project.

.. code-block::
curl -L https://api.github.com/repos/swagger-api/swagger-ui/tarball | tar -xv --directory=flask_rebar/swagger_ui/static --strip-components=2 "*/dist/"
Documentation
-------------

Expand Down
6 changes: 3 additions & 3 deletions flask_rebar/swagger_generation/authenticator_to_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ def get_security_schemes(self, obj, context):
OpenAPI Specification for defining security schemes
2.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-definitions-object
3.0.2: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#fixed-fields-6
3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#fixed-fields-6
(see securitySchemes field)
OpenAPI Specification for Security Scheme Object
2.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-scheme-object
3.0.2: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#security-scheme-object
3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#security-scheme-object
Example: An authenticator that makes use of an api_key and an application_key scheme
Expand Down Expand Up @@ -81,7 +81,7 @@ def get_security_requirements(self, obj, context):
OpenAPI Specification for Security Requirement Object
2.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object
3.0.2: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#security-requirement-object
3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#security-requirement-object
Example: Require oauth with scope "read:stuff" OR api_key AND application_key
[
Expand Down
45 changes: 27 additions & 18 deletions flask_rebar/swagger_generation/marshmallow_to_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,16 @@ def convert(self, obj, context):
)
)

if context.openapi_version == 3 and obj.allow_none:
jsonschema_obj["nullable"] = True

return jsonschema_obj

# With OpenApi 3.1 nullable has been removed entirely
# and allowing 'none' means we return an array of allowed types that includes sw.null
def null_type_determination(self, obj, context, sw_type):
if context.openapi_version == 3 and obj.allow_none:
return [sw_type, sw.null]
else:
return sw_type

@sets_swagger_attr(sw.default)
def get_default(self, obj, context):
if (
Expand Down Expand Up @@ -349,7 +354,7 @@ class ListConverter(FieldConverter):

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.array
return self.null_type_determination(obj, context, sw.array)

@sets_swagger_attr(sw.items)
def get_items(self, obj, context):
Expand All @@ -361,47 +366,47 @@ class DictConverter(FieldConverter):

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.object_
return self.null_type_determination(obj, context, sw.object_)


class IntegerConverter(FieldConverter):
MARSHMALLOW_TYPE = m.fields.Integer

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.integer
return self.null_type_determination(obj, context, sw.integer)


class StringConverter(FieldConverter):
MARSHMALLOW_TYPE = m.fields.String

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.string
return self.null_type_determination(obj, context, sw.string)


class NumberConverter(FieldConverter):
MARSHMALLOW_TYPE = m.fields.Number

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.number
return self.null_type_determination(obj, context, sw.number)


class BooleanConverter(FieldConverter):
MARSHMALLOW_TYPE = m.fields.Boolean

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.boolean
return self.null_type_determination(obj, context, sw.boolean)


class DateTimeConverter(FieldConverter):
MARSHMALLOW_TYPE = m.fields.DateTime

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.string
return self.null_type_determination(obj, context, sw.string)

@sets_swagger_attr(sw.format_)
def get_format(self, obj, context):
Expand All @@ -413,7 +418,7 @@ class UUIDConverter(FieldConverter):

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.string
return self.null_type_determination(obj, context, sw.string)

@sets_swagger_attr(sw.format_)
def get_format(self, obj, context):
Expand All @@ -425,7 +430,7 @@ class DateConverter(FieldConverter):

@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
return sw.string
return self.null_type_determination(obj, context, sw.string)

@sets_swagger_attr(sw.format_)
def get_format(self, obj, context):
Expand All @@ -438,7 +443,9 @@ class MethodConverter(FieldConverter):
@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
if "swagger_type" in obj.metadata:
return obj.metadata["swagger_type"]
return self.null_type_determination(
obj, context, obj.metadata["swagger_type"]
)
else:
raise ValueError(
'Must include "swagger_type" ' "keyword argument in Method field"
Expand All @@ -451,7 +458,9 @@ class FunctionConverter(FieldConverter):
@sets_swagger_attr(sw.type_)
def get_type(self, obj, context):
if "swagger_type" in obj.metadata:
return obj.metadata["swagger_type"]
return self.null_type_determination(
obj, context, obj.metadata["swagger_type"]
)
else:
raise ValueError(
'Must include "swagger_type" ' "keyword argument in Function field"
Expand Down Expand Up @@ -653,13 +662,13 @@ def get_type(self, obj, context):
# I'm going out on a limb and assuming your enum uses same type for all vals, else caveat emptor:
value_type = type(next(iter(obj.enum)).value)
if value_type is int:
return sw.integer
return self.null_type_determination(obj, context, sw.integer)
elif value_type is float:
return sw.number
return self.null_type_determination(obj, context, sw.number)
else:
return sw.string
return self.null_type_determination(obj, context, sw.string)
else:
return sw.string
return self.null_type_determination(obj, context, sw.string)

@sets_swagger_attr(sw.enum)
def get_enum(self, obj, context):
Expand Down
4 changes: 2 additions & 2 deletions flask_rebar/swagger_generation/swagger_generator_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


class SwaggerV3Generator(SwaggerGenerator):
"""Generates a v3.0.2 Swagger specification from a Rebar object.
"""Generates a v3.1.0 Swagger specification from a Rebar object.
Not all things are retrievable from the Rebar object, so this
guy also needs some additional information to complete the job.
Expand All @@ -49,7 +49,7 @@ class SwaggerV3Generator(SwaggerGenerator):
A list of Server Objects to set as the server metadata for the specification.
"""

_open_api_version = "3.0.2"
_open_api_version = "3.1.0"

def __init__(
self,
Expand Down
Binary file modified flask_rebar/swagger_ui/static/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified flask_rebar/swagger_ui/static/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions flask_rebar/swagger_ui/static/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*,
*:before,
*:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}
19 changes: 19 additions & 0 deletions flask_rebar/swagger_ui/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>

<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>
40 changes: 26 additions & 14 deletions flask_rebar/swagger_ui/static/oauth2-redirect.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<!doctype html>
<html lang="en-US">
<body onload="run()">
</body>
</html>
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
Expand All @@ -12,31 +13,32 @@
var isValid, qp, arr;

if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}

arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
return key === "" ? value : decodeURIComponent(value);
}
) : {}
) : {};

isValid = qp.state === sentState
isValid = qp.state === sentState;

if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}

Expand All @@ -45,7 +47,7 @@
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
Expand All @@ -56,12 +58,22 @@
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}

if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>
20 changes: 20 additions & 0 deletions flask_rebar/swagger_ui/static/swagger-initializer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">

// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});

//</editor-fold>
};
100 changes: 2 additions & 98 deletions flask_rebar/swagger_ui/static/swagger-ui-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion flask_rebar/swagger_ui/static/swagger-ui-bundle.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions flask_rebar/swagger_ui/static/swagger-ui-es-bundle-core.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions flask_rebar/swagger_ui/static/swagger-ui-es-bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions flask_rebar/swagger_ui/static/swagger-ui-es-bundle.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit 03e660c

Please sign in to comment.