Merge branch 'master' of github.com:swagger-api/swagger-ui into ft/performance
This commit is contained in:
@@ -16,7 +16,8 @@
|
|||||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"react"
|
"react",
|
||||||
|
"mocha"
|
||||||
],
|
],
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
"comma-dangle": 0,
|
"comma-dangle": 0,
|
||||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||||
"react/jsx-no-bind": 1,
|
"react/jsx-no-bind": 1,
|
||||||
"react/display-name": 0
|
"react/display-name": 0,
|
||||||
|
"mocha/no-exclusive-tests": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
|
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
|
||||||
|
|
||||||
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first contribution](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+contribution%22) label.
|
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first issue](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22) label.
|
||||||
|
|
||||||
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
|
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
|
||||||
|
|
||||||
This repo publishes to two different NPM packages:
|
This repository publishes to two different NPM modules:
|
||||||
|
|
||||||
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is intended for use as a node module.
|
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is a traditional npm module intended for use in JavaScript web application projects that are capable of resolving dependencies (via Webpack, Browserify, etc).
|
||||||
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) comes pre-bundled with all dependencies and can be incorporated directly in a webapp.
|
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) is a dependency-free module that includes everything you need to serve Swagger-UI in a server-side project, or a web project that can't resolve npm module dependencies.
|
||||||
|
|
||||||
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
|
|||||||
|
|
||||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||||
------------------ | ------------ | -------------------------- | -----
|
------------------ | ------------ | -------------------------- | -----
|
||||||
3.2.0 | 2017-09-08 | 2.0, 3.0 | [tag v3.2.0](https://github.com/swagger-api/swagger-ui/tree/v3.2.0)
|
3.4.0 | 2017-10-20 | 2.0, 3.0 | [tag v3.4.0](https://github.com/swagger-api/swagger-ui/tree/v3.4.0)
|
||||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||||
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
||||||
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
||||||
@@ -119,7 +119,7 @@ scopeSeparator | scope separator for passing scopes, encoded before calling, def
|
|||||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||||
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`
|
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`
|
||||||
|
|
||||||
```
|
```javascript
|
||||||
const ui = SwaggerUIBundle({...})
|
const ui = SwaggerUIBundle({...})
|
||||||
|
|
||||||
// Method can be called in any place after calling constructor SwaggerUIBundle
|
// Method can be called in any place after calling constructor SwaggerUIBundle
|
||||||
@@ -151,6 +151,8 @@ domNode | The HTML DOM element inside which SwaggerUi will put the user interfac
|
|||||||
oauth2RedirectUrl | OAuth redirect URL
|
oauth2RedirectUrl | OAuth redirect URL
|
||||||
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
||||||
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||||
|
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be set to 'model' or 'example', and the default is 'example'.
|
||||||
|
defaultModelExpandDepth | The default expansion depth for models. The default value is 1.
|
||||||
configUrl | Configs URL
|
configUrl | Configs URL
|
||||||
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||||
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||||
@@ -169,7 +171,7 @@ showMutatedRequest | If set to `true` (the default), uses the mutated request re
|
|||||||
#### Topbar plugin
|
#### Topbar plugin
|
||||||
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
|
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
|
||||||
|
|
||||||
```
|
```javascript
|
||||||
let preset = [
|
let preset = [
|
||||||
// TopbarPlugin,
|
// TopbarPlugin,
|
||||||
ConfigsPlugin,
|
ConfigsPlugin,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Swagger UI</title>
|
<title>Swagger UI</title>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||||
|
|||||||
@@ -27,7 +27,10 @@
|
|||||||
|
|
||||||
isValid = qp.state === sentState
|
isValid = qp.state === sentState
|
||||||
|
|
||||||
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
|
if ((
|
||||||
|
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||||
|
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||||
|
) && !oauth2.auth.code) {
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
oauth2.errCb({
|
oauth2.errCb({
|
||||||
authId: oauth2.auth.name,
|
authId: oauth2.auth.name,
|
||||||
|
|||||||
5
dist/oauth2-redirect.html
vendored
5
dist/oauth2-redirect.html
vendored
@@ -27,7 +27,10 @@
|
|||||||
|
|
||||||
isValid = qp.state === sentState
|
isValid = qp.state === sentState
|
||||||
|
|
||||||
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
|
if ((
|
||||||
|
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||||
|
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||||
|
) && !oauth2.auth.code) {
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
oauth2.errCb({
|
oauth2.errCb({
|
||||||
authId: oauth2.auth.name,
|
authId: oauth2.auth.name,
|
||||||
|
|||||||
94
dist/swagger-ui-bundle.js
vendored
94
dist/swagger-ui-bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-bundle.js.map
vendored
2
dist/swagger-ui-bundle.js.map
vendored
File diff suppressed because one or more lines are too long
6
dist/swagger-ui-standalone-preset.js
vendored
6
dist/swagger-ui-standalone-preset.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-standalone-preset.js.map
vendored
2
dist/swagger-ui-standalone-preset.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.css
vendored
2
dist/swagger-ui.css
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.css.map
vendored
2
dist/swagger-ui.css.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui.css","sources":[],"mappings":"","sourceRoot":""}
|
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
|
||||||
4
dist/swagger-ui.js
vendored
4
dist/swagger-ui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.js.map
vendored
2
dist/swagger-ui.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -137,7 +137,7 @@ module.exports = function(rules, options) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
devtool: specialOptions.sourcemaps ? "cheap-module-source-map" : null,
|
devtool: specialOptions.sourcemaps ? "nosource-source-map" : null,
|
||||||
|
|
||||||
plugins,
|
plugins,
|
||||||
|
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "swagger-ui",
|
"name": "swagger-ui",
|
||||||
"version": "3.2.0",
|
"version": "3.4.0",
|
||||||
"main": "dist/swagger-ui.js",
|
"main": "dist/swagger-ui.js",
|
||||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"test": "npm run lint-errors && npm run just-test-in-node",
|
"test": "npm run lint-errors && npm run just-test-in-node",
|
||||||
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
||||||
"just-test": "karma start --config karma.conf.js",
|
"just-test": "karma start --config karma.conf.js",
|
||||||
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package",
|
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package test/xss",
|
||||||
"test-e2e": "sleep 3 && nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json",
|
"test-e2e": "sleep 3 && nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json",
|
||||||
"e2e-initial-render": "nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json --group initial-render",
|
"e2e-initial-render": "nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json --group initial-render",
|
||||||
"mock-api": "json-server --watch test/e2e/db.json --port 3204",
|
"mock-api": "json-server --watch test/e2e/db.json --port 3204",
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
"base64-js": "^1.2.0",
|
"base64-js": "^1.2.0",
|
||||||
"brace": "0.7.0",
|
"brace": "0.7.0",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
|
"commonmark": "^0.28.1",
|
||||||
"css.escape": "1.5.1",
|
"css.escape": "1.5.1",
|
||||||
"deep-extend": "0.4.1",
|
"deep-extend": "0.4.1",
|
||||||
"expect": "1.20.2",
|
"expect": "1.20.2",
|
||||||
@@ -67,17 +68,17 @@
|
|||||||
"react-motion": "0.4.4",
|
"react-motion": "0.4.4",
|
||||||
"react-object-inspector": "0.2.1",
|
"react-object-inspector": "0.2.1",
|
||||||
"react-redux": "^4.x.x",
|
"react-redux": "^4.x.x",
|
||||||
"react-remarkable": "1.1.1",
|
|
||||||
"react-split-pane": "0.1.57",
|
"react-split-pane": "0.1.57",
|
||||||
"redux": "^3.x.x",
|
"redux": "^3.x.x",
|
||||||
"redux-immutable": "3.0.8",
|
"redux-immutable": "3.0.8",
|
||||||
"redux-logger": "*",
|
"redux-logger": "*",
|
||||||
|
"remarkable": "^1.7.1",
|
||||||
"reselect": "2.5.3",
|
"reselect": "2.5.3",
|
||||||
"sanitize-html": "^1.14.1",
|
"sanitize-html": "^1.14.1",
|
||||||
"scroll-to-element": "^2.0.0",
|
"scroll-to-element": "^2.0.0",
|
||||||
"serialize-error": "2.0.0",
|
"serialize-error": "2.0.0",
|
||||||
"shallowequal": "0.2.2",
|
"shallowequal": "0.2.2",
|
||||||
"swagger-client": "3.1.0",
|
"swagger-client": "^3.3.0",
|
||||||
"url-parse": "^1.1.8",
|
"url-parse": "^1.1.8",
|
||||||
"whatwg-fetch": "0.11.1",
|
"whatwg-fetch": "0.11.1",
|
||||||
"worker-loader": "^0.7.1",
|
"worker-loader": "^0.7.1",
|
||||||
@@ -104,6 +105,7 @@
|
|||||||
"enzyme": "^2.7.1",
|
"enzyme": "^2.7.1",
|
||||||
"eslint": "^4.1.1",
|
"eslint": "^4.1.1",
|
||||||
"eslint-plugin-import": "^2.6.0",
|
"eslint-plugin-import": "^2.6.0",
|
||||||
|
"eslint-plugin-mocha": "^4.11.0",
|
||||||
"eslint-plugin-react": "^7.1.0",
|
"eslint-plugin-react": "^7.1.0",
|
||||||
"extract-text-webpack-plugin": "^2.1.2",
|
"extract-text-webpack-plugin": "^2.1.2",
|
||||||
"file-loader": "0.11.2",
|
"file-loader": "0.11.2",
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ export default class ArrayModel extends Component {
|
|||||||
|
|
||||||
render(){
|
render(){
|
||||||
let { getComponent, schema, depth, expandDepth, name } = this.props
|
let { getComponent, schema, depth, expandDepth, name } = this.props
|
||||||
|
let description = schema.get("description")
|
||||||
let items = schema.get("items")
|
let items = schema.get("items")
|
||||||
let title = schema.get("title") || name
|
let title = schema.get("title") || name
|
||||||
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
|
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref"].indexOf(key) === -1 )
|
||||||
|
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
const ModelCollapse = getComponent("ModelCollapse")
|
const ModelCollapse = getComponent("ModelCollapse")
|
||||||
const Model = getComponent("Model")
|
const Model = getComponent("Model")
|
||||||
|
|
||||||
@@ -36,15 +38,17 @@ export default class ArrayModel extends Component {
|
|||||||
return <span className="model">
|
return <span className="model">
|
||||||
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
||||||
[
|
[
|
||||||
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
|
|
||||||
]
|
|
||||||
{
|
{
|
||||||
properties.size ? <span>
|
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
|
||||||
{ properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}>
|
<br />{ key }: { String(v) }</span>)
|
||||||
<br />{ `${key}:`}{ String(v) }</span>)
|
|
||||||
}<br /></span>
|
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
!description ? null :
|
||||||
|
<Markdown source={ description } />
|
||||||
|
}
|
||||||
|
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
|
||||||
|
]
|
||||||
</ModelCollapse>
|
</ModelCollapse>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,14 +51,15 @@ export default class ApiKeyAuth extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h4>Api key authorization<JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
<h4>
|
||||||
|
<code>{ name || schema.get("name") }</code>
|
||||||
|
(apiKey)
|
||||||
|
<JumpToPath path={[ "securityDefinitions", name ]} />
|
||||||
|
</h4>
|
||||||
{ value && <h6>Authorized</h6>}
|
{ value && <h6>Authorized</h6>}
|
||||||
<Row>
|
<Row>
|
||||||
<Markdown source={ schema.get("description") } />
|
<Markdown source={ schema.get("description") } />
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
|
||||||
<p>Name: <code>{ schema.get("name") }</code></p>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
<Row>
|
||||||
<p>In: <code>{ schema.get("in") }</code></p>
|
<p>In: <code>{ schema.get("in") }</code></p>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
62
src/core/components/auth/auth-item.jsx
Normal file
62
src/core/components/auth/auth-item.jsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
|
||||||
|
export default class Auths extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
schema: ImPropTypes.orderedMap.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
onAuthChange: PropTypes.func.isRequired,
|
||||||
|
authorized: ImPropTypes.orderedMap.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let {
|
||||||
|
schema,
|
||||||
|
name,
|
||||||
|
getComponent,
|
||||||
|
onAuthChange,
|
||||||
|
authorized,
|
||||||
|
errSelectors
|
||||||
|
} = this.props
|
||||||
|
const ApiKeyAuth = getComponent("apiKeyAuth")
|
||||||
|
const BasicAuth = getComponent("basicAuth")
|
||||||
|
|
||||||
|
let authEl
|
||||||
|
|
||||||
|
const type = schema.get("type")
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case "apiKey": authEl = <ApiKeyAuth key={ name }
|
||||||
|
schema={ schema }
|
||||||
|
name={ name }
|
||||||
|
errSelectors={ errSelectors }
|
||||||
|
authorized={ authorized }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
onChange={ onAuthChange } />
|
||||||
|
break
|
||||||
|
case "basic": authEl = <BasicAuth key={ name }
|
||||||
|
schema={ schema }
|
||||||
|
name={ name }
|
||||||
|
errSelectors={ errSelectors }
|
||||||
|
authorized={ authorized }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
onChange={ onAuthChange } />
|
||||||
|
break
|
||||||
|
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<div key={`${name}-jump`}>
|
||||||
|
{ authEl }
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
errSelectors: PropTypes.object.isRequired,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
authSelectors: PropTypes.object.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
authActions: PropTypes.object.isRequired,
|
||||||
|
definitions: ImPropTypes.iterable.isRequired
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ export default class Auths extends React.Component {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
let { authActions } = this.props
|
let { authActions } = this.props
|
||||||
|
|
||||||
authActions.authorize(this.state)
|
authActions.authorize(this.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +43,7 @@ export default class Auths extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { definitions, getComponent, authSelectors, errSelectors } = this.props
|
let { definitions, getComponent, authSelectors, errSelectors } = this.props
|
||||||
const ApiKeyAuth = getComponent("apiKeyAuth")
|
const AuthItem = getComponent("AuthItem")
|
||||||
const BasicAuth = getComponent("basicAuth")
|
|
||||||
const Oauth2 = getComponent("oauth2", true)
|
const Oauth2 = getComponent("oauth2", true)
|
||||||
const Button = getComponent("Button")
|
const Button = getComponent("Button")
|
||||||
|
|
||||||
@@ -64,33 +62,15 @@ export default class Auths extends React.Component {
|
|||||||
!!nonOauthDefinitions.size && <form onSubmit={ this.submitAuth }>
|
!!nonOauthDefinitions.size && <form onSubmit={ this.submitAuth }>
|
||||||
{
|
{
|
||||||
nonOauthDefinitions.map( (schema, name) => {
|
nonOauthDefinitions.map( (schema, name) => {
|
||||||
let type = schema.get("type")
|
return <AuthItem
|
||||||
let authEl
|
key={name}
|
||||||
|
schema={schema}
|
||||||
switch(type) {
|
name={name}
|
||||||
case "apiKey": authEl = <ApiKeyAuth key={ name }
|
getComponent={getComponent}
|
||||||
schema={ schema }
|
onAuthChange={this.onAuthChange}
|
||||||
name={ name }
|
authorized={authorized}
|
||||||
errSelectors={ errSelectors }
|
errSelectors={errSelectors}
|
||||||
authorized={ authorized }
|
/>
|
||||||
getComponent={ getComponent }
|
|
||||||
onChange={ this.onAuthChange } />
|
|
||||||
break
|
|
||||||
case "basic": authEl = <BasicAuth key={ name }
|
|
||||||
schema={ schema }
|
|
||||||
name={ name }
|
|
||||||
errSelectors={ errSelectors }
|
|
||||||
authorized={ authorized }
|
|
||||||
getComponent={ getComponent }
|
|
||||||
onChange={ this.onAuthChange } />
|
|
||||||
break
|
|
||||||
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<div key={`${name}-jump`}>
|
|
||||||
{ authEl }
|
|
||||||
</div>)
|
|
||||||
|
|
||||||
}).toArray()
|
}).toArray()
|
||||||
}
|
}
|
||||||
<div className="auth-btn-wrapper">
|
<div className="auth-btn-wrapper">
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ import React from "react"
|
|||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import oauth2Authorize from "core/oauth2-authorize"
|
import oauth2Authorize from "core/oauth2-authorize"
|
||||||
|
|
||||||
const IMPLICIT = "implicit"
|
|
||||||
const ACCESS_CODE = "accessCode"
|
|
||||||
const PASSWORD = "password"
|
|
||||||
const APPLICATION = "application"
|
|
||||||
|
|
||||||
export default class Oauth2 extends React.Component {
|
export default class Oauth2 extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
@@ -16,6 +11,7 @@ export default class Oauth2 extends React.Component {
|
|||||||
authSelectors: PropTypes.object.isRequired,
|
authSelectors: PropTypes.object.isRequired,
|
||||||
authActions: PropTypes.object.isRequired,
|
authActions: PropTypes.object.isRequired,
|
||||||
errSelectors: PropTypes.object.isRequired,
|
errSelectors: PropTypes.object.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
errActions: PropTypes.object.isRequired,
|
errActions: PropTypes.object.isRequired,
|
||||||
getConfigs: PropTypes.any
|
getConfigs: PropTypes.any
|
||||||
}
|
}
|
||||||
@@ -83,7 +79,9 @@ export default class Oauth2 extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { schema, getComponent, authSelectors, errSelectors, name } = this.props
|
let {
|
||||||
|
schema, getComponent, authSelectors, errSelectors, name, specSelectors
|
||||||
|
} = this.props
|
||||||
const Input = getComponent("Input")
|
const Input = getComponent("Input")
|
||||||
const Row = getComponent("Row")
|
const Row = getComponent("Row")
|
||||||
const Col = getComponent("Col")
|
const Col = getComponent("Col")
|
||||||
@@ -92,6 +90,14 @@ export default class Oauth2 extends React.Component {
|
|||||||
const JumpToPath = getComponent("JumpToPath", true)
|
const JumpToPath = getComponent("JumpToPath", true)
|
||||||
const Markdown = getComponent( "Markdown" )
|
const Markdown = getComponent( "Markdown" )
|
||||||
|
|
||||||
|
const { isOAS3 } = specSelectors
|
||||||
|
|
||||||
|
// Auth type consts
|
||||||
|
const IMPLICIT = "implicit"
|
||||||
|
const PASSWORD = "password"
|
||||||
|
const ACCESS_CODE = isOAS3() ? "authorizationCode" : "accessCode"
|
||||||
|
const APPLICATION = isOAS3() ? "clientCredentials" : "application"
|
||||||
|
|
||||||
let flow = schema.get("flow")
|
let flow = schema.get("flow")
|
||||||
let scopes = schema.get("allowedScopes") || schema.get("scopes")
|
let scopes = schema.get("allowedScopes") || schema.get("scopes")
|
||||||
let authorizedAuth = authSelectors.authorized().get(name)
|
let authorizedAuth = authSelectors.authorized().get(name)
|
||||||
@@ -102,7 +108,7 @@ export default class Oauth2 extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h4>OAuth2.0 <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
<h4>{name} (OAuth2, { schema.get("flow") }) <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
||||||
{ !this.state.appName ? null : <h5>Application: { this.state.appName } </h5> }
|
{ !this.state.appName ? null : <h5>Application: { this.state.appName } </h5> }
|
||||||
{ description && <Markdown source={ schema.get("description") } /> }
|
{ description && <Markdown source={ schema.get("description") } /> }
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ export default class LiveResponse extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ curlRequest && <Curl request={ curlRequest }/> }
|
{ curlRequest && <Curl request={ curlRequest }/> }
|
||||||
|
{ url && <div>
|
||||||
|
<h4>Request URL</h4>
|
||||||
|
<div className="request-url">
|
||||||
|
<pre>{url}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<h4>Server response</h4>
|
<h4>Server response</h4>
|
||||||
<table className="responses-table">
|
<table className="responses-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -7,14 +7,19 @@ export default class ModelExample extends React.Component {
|
|||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
schema: PropTypes.object.isRequired,
|
schema: PropTypes.object.isRequired,
|
||||||
example: PropTypes.any.isRequired,
|
example: PropTypes.any.isRequired,
|
||||||
isExecute: PropTypes.bool
|
isExecute: PropTypes.bool,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context)
|
super(props, context)
|
||||||
|
let { getConfigs } = this.props
|
||||||
|
let { defaultModelRendering } = getConfigs()
|
||||||
|
if (defaultModelRendering !== "example" && defaultModelRendering !== "model") {
|
||||||
|
defaultModelRendering = "example"
|
||||||
|
}
|
||||||
this.state = {
|
this.state = {
|
||||||
activeTab: "example"
|
activeTab: defaultModelRendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +32,8 @@ export default class ModelExample extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { getComponent, specSelectors, schema, example, isExecute } = this.props
|
let { getComponent, specSelectors, schema, example, isExecute, getConfigs } = this.props
|
||||||
|
let { defaultModelExpandDepth } = getConfigs()
|
||||||
const ModelWrapper = getComponent("ModelWrapper")
|
const ModelWrapper = getComponent("ModelWrapper")
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
@@ -47,7 +53,7 @@ export default class ModelExample extends React.Component {
|
|||||||
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
|
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
expandDepth={ 1 } />
|
expandDepth={ defaultModelExpandDepth } />
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default class Models extends Component {
|
|||||||
render(){
|
render(){
|
||||||
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
||||||
let definitions = specSelectors.definitions()
|
let definitions = specSelectors.definitions()
|
||||||
let { docExpansion } = getConfigs()
|
let { docExpansion, defaultModelExpandDepth } = getConfigs()
|
||||||
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
||||||
|
|
||||||
const ModelWrapper = getComponent("ModelWrapper")
|
const ModelWrapper = getComponent("ModelWrapper")
|
||||||
@@ -33,6 +33,7 @@ export default class Models extends Component {
|
|||||||
definitions.entrySeq().map( ( [ name, model ])=>{
|
definitions.entrySeq().map( ( [ name, model ])=>{
|
||||||
return <div className="model-container" key={ `models-section-${name}` }>
|
return <div className="model-container" key={ `models-section-${name}` }>
|
||||||
<ModelWrapper name={ name }
|
<ModelWrapper name={ name }
|
||||||
|
expandDepth={ defaultModelExpandDepth }
|
||||||
schema={ model }
|
schema={ model }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
specSelectors={ specSelectors }/>
|
specSelectors={ specSelectors }/>
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export default class Operation extends PureComponent {
|
|||||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||||
|
|
||||||
// Merge in Live Response
|
// Merge in Live Response
|
||||||
if(response && response.size > 0) {
|
if(responses && response && response.size > 0) {
|
||||||
let notDocumented = !responses.get(String(response.get("status")))
|
let notDocumented = !responses.get(String(response.get("status")))
|
||||||
response = response.set("notDocumented", notDocumented)
|
response = response.set("notDocumented", notDocumented)
|
||||||
}
|
}
|
||||||
@@ -224,6 +224,7 @@ export default class Operation extends PureComponent {
|
|||||||
specActions={ specActions }
|
specActions={ specActions }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
pathMethod={ [path, method] }
|
pathMethod={ [path, method] }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
|
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export default class Operations extends React.Component {
|
|||||||
|
|
||||||
const Operation = getComponent("operation")
|
const Operation = getComponent("operation")
|
||||||
const Collapse = getComponent("Collapse")
|
const Collapse = getComponent("Collapse")
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
|
|
||||||
let showSummary = layoutSelectors.showSummary()
|
let showSummary = layoutSelectors.showSummary()
|
||||||
let {
|
let {
|
||||||
@@ -89,7 +90,7 @@ export default class Operations extends React.Component {
|
|||||||
</a>
|
</a>
|
||||||
{ !tagDescription ? null :
|
{ !tagDescription ? null :
|
||||||
<small>
|
<small>
|
||||||
{ tagDescription }
|
<Markdown source={tagDescription} />
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
|
|||||||
|
|
||||||
updateValues = (props) => {
|
updateValues = (props) => {
|
||||||
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
|
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
|
||||||
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : {}
|
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : {}
|
||||||
let isXml = /xml/i.test(consumesValue)
|
let isXml = /xml/i.test(consumesValue)
|
||||||
let isJson = /json/i.test(consumesValue)
|
let isJson = /json/i.test(consumesValue)
|
||||||
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
||||||
@@ -107,7 +107,7 @@ export default class ParamBody extends PureComponent {
|
|||||||
const HighlightCode = getComponent("highlightCode")
|
const HighlightCode = getComponent("highlightCode")
|
||||||
const ContentType = getComponent("contentType")
|
const ContentType = getComponent("contentType")
|
||||||
// for domains where specSelectors not passed
|
// for domains where specSelectors not passed
|
||||||
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : param
|
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : param
|
||||||
let errors = parameter.get("errors", List())
|
let errors = parameter.get("errors", List())
|
||||||
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
|
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
|
||||||
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
|
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ export default class ParameterRow extends Component {
|
|||||||
isExecute: PropTypes.bool,
|
isExecute: PropTypes.bool,
|
||||||
onChangeConsumes: PropTypes.func.isRequired,
|
onChangeConsumes: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
pathMethod: PropTypes.array.isRequired
|
pathMethod: PropTypes.array.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@@ -19,7 +20,7 @@ export default class ParameterRow extends Component {
|
|||||||
|
|
||||||
let { specSelectors, pathMethod, param } = props
|
let { specSelectors, pathMethod, param } = props
|
||||||
let defaultValue = param.get("default")
|
let defaultValue = param.get("default")
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let value = parameter ? parameter.get("value") : ""
|
let value = parameter ? parameter.get("value") : ""
|
||||||
if ( defaultValue !== undefined && value === undefined ) {
|
if ( defaultValue !== undefined && value === undefined ) {
|
||||||
this.onChangeWrapper(defaultValue)
|
this.onChangeWrapper(defaultValue)
|
||||||
@@ -30,7 +31,7 @@ export default class ParameterRow extends Component {
|
|||||||
let { specSelectors, pathMethod, param } = props
|
let { specSelectors, pathMethod, param } = props
|
||||||
let example = param.get("example")
|
let example = param.get("example")
|
||||||
let defaultValue = param.get("default")
|
let defaultValue = param.get("default")
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let paramValue = parameter ? parameter.get("value") : undefined
|
let paramValue = parameter ? parameter.get("value") : undefined
|
||||||
let enumValue = parameter ? parameter.get("enum") : undefined
|
let enumValue = parameter ? parameter.get("enum") : undefined
|
||||||
let value
|
let value
|
||||||
@@ -56,7 +57,7 @@ export default class ParameterRow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
let {param, onChange, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
||||||
|
|
||||||
let { isOAS3 } = specSelectors
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ export default class ParameterRow extends Component {
|
|||||||
let isFormDataSupported = "FormData" in win
|
let isFormDataSupported = "FormData" in win
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
|
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let value = parameter ? parameter.get("value") : ""
|
let value = parameter ? parameter.get("value") : ""
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -114,12 +115,13 @@ export default class ParameterRow extends Component {
|
|||||||
required={ required }
|
required={ required }
|
||||||
description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`}
|
description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`}
|
||||||
onChange={ this.onChangeWrapper }
|
onChange={ this.onChangeWrapper }
|
||||||
schema={ param }/>
|
schema={ isOAS3 && isOAS3() ? param.get("schema") : param }/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
bodyParam && schema ? <ModelExample getComponent={ getComponent }
|
bodyParam && schema ? <ModelExample getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
isExecute={ isExecute }
|
isExecute={ isExecute }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
schema={ schema }
|
schema={ schema }
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ export default class Parameters extends Component {
|
|||||||
onTryoutClick: PropTypes.func,
|
onTryoutClick: PropTypes.func,
|
||||||
onCancelClick: PropTypes.func,
|
onCancelClick: PropTypes.func,
|
||||||
onChangeKey: PropTypes.array,
|
onChangeKey: PropTypes.array,
|
||||||
pathMethod: PropTypes.array.isRequired
|
pathMethod: PropTypes.array.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ export default class Parameters extends Component {
|
|||||||
onChangeKey,
|
onChangeKey,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
changeParam( onChangeKey, param.get("name"), value, isXml)
|
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeConsumesWrapper = ( val ) => {
|
onChangeConsumesWrapper = ( val ) => {
|
||||||
@@ -60,6 +61,7 @@ export default class Parameters extends Component {
|
|||||||
|
|
||||||
fn,
|
fn,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
pathMethod
|
pathMethod
|
||||||
} = this.props
|
} = this.props
|
||||||
@@ -93,8 +95,9 @@ export default class Parameters extends Component {
|
|||||||
eachMap(parameters, (parameter) => (
|
eachMap(parameters, (parameter) => (
|
||||||
<ParameterRow fn={ fn }
|
<ParameterRow fn={ fn }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
param={ parameter }
|
param={ parameter }
|
||||||
key={ parameter.get( "name" ) }
|
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
|
||||||
onChange={ this.onChange }
|
onChange={ this.onChange }
|
||||||
onChangeConsumes={this.onChangeConsumesWrapper}
|
onChangeConsumes={this.onChangeConsumesWrapper}
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default class Primitive extends Component {
|
|||||||
let format = schema.get("format")
|
let format = schema.get("format")
|
||||||
let xml = schema.get("xml")
|
let xml = schema.get("xml")
|
||||||
let enumArray = schema.get("enum")
|
let enumArray = schema.get("enum")
|
||||||
|
let title = schema.get("title") || name
|
||||||
let description = schema.get("description")
|
let description = schema.get("description")
|
||||||
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
@@ -30,7 +31,7 @@ export default class Primitive extends Component {
|
|||||||
|
|
||||||
return <span className="model">
|
return <span className="model">
|
||||||
<span className="prop">
|
<span className="prop">
|
||||||
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ name }</span> }
|
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ title }</span> }
|
||||||
<span className="prop-type">{ type }</span>
|
<span className="prop-type">{ type }</span>
|
||||||
{ format && <span className="prop-format">(${format})</span>}
|
{ format && <span className="prop-format">(${format})</span>}
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import Remarkable from "react-remarkable"
|
import Remarkable from "remarkable"
|
||||||
import sanitize from "sanitize-html"
|
import sanitize from "sanitize-html"
|
||||||
|
|
||||||
function Markdown({ source }) {
|
function Markdown({ source }) {
|
||||||
const sanitized = sanitizer(source)
|
const html = new Remarkable({
|
||||||
|
html: true,
|
||||||
|
typographer: true,
|
||||||
|
breaks: true,
|
||||||
|
linkify: true,
|
||||||
|
linkTarget: "_blank"
|
||||||
|
}).render(source)
|
||||||
|
const sanitized = sanitizer(html)
|
||||||
|
|
||||||
// sometimes the sanitizer returns "undefined" as a string
|
if ( !source || !html || !sanitized ) {
|
||||||
if(!source || !sanitized || sanitized === "undefined") {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="markdown">
|
return (
|
||||||
<Remarkable
|
<div className="markdown" dangerouslySetInnerHTML={{ __html: sanitized }}></div>
|
||||||
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
|
)
|
||||||
source={sanitized}
|
|
||||||
></Remarkable>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Markdown.propTypes = {
|
Markdown.propTypes = {
|
||||||
@@ -26,9 +29,13 @@ Markdown.propTypes = {
|
|||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
||||||
const sanitizeOptions = {
|
const sanitizeOptions = {
|
||||||
|
allowedTags: sanitize.defaults.allowedTags.concat([ "h1", "h2", "img" ]),
|
||||||
|
allowedAttributes: {
|
||||||
|
...sanitize.defaults.allowedAttributes,
|
||||||
|
"img": sanitize.defaults.allowedAttributes.img.concat(["title"])
|
||||||
|
},
|
||||||
textFilter: function(text) {
|
textFilter: function(text) {
|
||||||
return text
|
return text.replace(/"/g, "\"")
|
||||||
.replace(/"/g, "\"")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ export default class ResponseBody extends React.Component {
|
|||||||
// Download
|
// Download
|
||||||
} else if (
|
} else if (
|
||||||
/^application\/octet-stream/i.test(contentType) ||
|
/^application\/octet-stream/i.test(contentType) ||
|
||||||
headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"]) ||
|
(headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"])) ||
|
||||||
headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"]) ||
|
(headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"])) ||
|
||||||
headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"]) ||
|
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
|
||||||
headers["content-description"] && (/File Transfer/i).test(headers["content-description"])) {
|
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
|
||||||
|
|
||||||
let contentLength = headers["content-length"] || headers["Content-Length"]
|
let contentLength = headers["content-length"] || headers["Content-Length"]
|
||||||
if ( !(+contentLength) ) return null
|
if ( !(+contentLength) ) return null
|
||||||
@@ -83,8 +83,12 @@ export default class ResponseBody extends React.Component {
|
|||||||
// Anything else (CORS)
|
// Anything else (CORS)
|
||||||
} else if (typeof content === "string") {
|
} else if (typeof content === "string") {
|
||||||
bodyEl = <HighlightCode value={ content } />
|
bodyEl = <HighlightCode value={ content } />
|
||||||
} else {
|
} else if ( content.size > 0 ) {
|
||||||
|
// We don't know the contentType, but there was some content returned
|
||||||
bodyEl = <div>Unknown response type</div>
|
bodyEl = <div>Unknown response type</div>
|
||||||
|
} else {
|
||||||
|
// We don't know the contentType and there was no content returned
|
||||||
|
bodyEl = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( !bodyEl ? null : <div>
|
return ( !bodyEl ? null : <div>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export default class Response extends React.Component {
|
|||||||
response: PropTypes.object,
|
response: PropTypes.object,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
fn: PropTypes.object.isRequired,
|
fn: PropTypes.object.isRequired,
|
||||||
contentType: PropTypes.string,
|
contentType: PropTypes.string,
|
||||||
@@ -73,6 +74,7 @@ export default class Response extends React.Component {
|
|||||||
className,
|
className,
|
||||||
fn,
|
fn,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
contentType,
|
contentType,
|
||||||
controlsAcceptHeader
|
controlsAcceptHeader
|
||||||
@@ -107,6 +109,14 @@ export default class Response extends React.Component {
|
|||||||
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
||||||
}) : null
|
}) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(examples) {
|
||||||
|
examples = examples.map(example => {
|
||||||
|
// Remove unwanted properties from examples
|
||||||
|
return example.set ? example.set("$$ref", undefined) : example
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -136,6 +146,7 @@ export default class Response extends React.Component {
|
|||||||
{ example ? (
|
{ example ? (
|
||||||
<ModelExample
|
<ModelExample
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
schema={ fromJSOrdered(schema) }
|
schema={ fromJSOrdered(schema) }
|
||||||
example={ example }/>
|
example={ example }/>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ export default class Responses extends React.Component {
|
|||||||
produces: PropTypes.object,
|
produces: PropTypes.object,
|
||||||
producesValue: PropTypes.any,
|
producesValue: PropTypes.any,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
oas3Actions: PropTypes.object.isRequired,
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
pathMethod: PropTypes.array.isRequired,
|
pathMethod: PropTypes.array.isRequired,
|
||||||
displayRequestDuration: PropTypes.bool.isRequired,
|
displayRequestDuration: PropTypes.bool.isRequired,
|
||||||
fn: PropTypes.object.isRequired,
|
fn: PropTypes.object.isRequired
|
||||||
getConfigs: PropTypes.func.isRequired
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -116,6 +116,7 @@ export default class Responses extends React.Component {
|
|||||||
controlsAcceptHeader={response === acceptControllingResponse}
|
controlsAcceptHeader={response === acceptControllingResponse}
|
||||||
onContentTypeChange={this.onResponseContentTypeChange}
|
onContentTypeChange={this.onResponseContentTypeChange}
|
||||||
contentType={ producesValue }
|
contentType={ producesValue }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
getComponent={ getComponent }/>
|
getComponent={ getComponent }/>
|
||||||
)
|
)
|
||||||
}).toArray()
|
}).toArray()
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
requestInterceptor: (a => a),
|
requestInterceptor: (a => a),
|
||||||
responseInterceptor: (a => a),
|
responseInterceptor: (a => a),
|
||||||
showMutatedRequest: true,
|
showMutatedRequest: true,
|
||||||
|
defaultModelRendering: "example",
|
||||||
|
defaultModelExpandDepth: 1,
|
||||||
|
|
||||||
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
||||||
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ export default function authorize ( { auth, authActions, errActions, configs, au
|
|||||||
case "implicit":
|
case "implicit":
|
||||||
query.push("response_type=token")
|
query.push("response_type=token")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case "clientCredentials":
|
||||||
|
// OAS3
|
||||||
|
authActions.authorizeApplication(auth)
|
||||||
|
return
|
||||||
|
|
||||||
|
case "authorizationCode":
|
||||||
|
// OAS3
|
||||||
|
query.push("response_type=code")
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof clientId === "string") {
|
if (typeof clientId === "string") {
|
||||||
@@ -64,7 +74,8 @@ export default function authorize ( { auth, authActions, errActions, configs, au
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = [schema.get("authorizationUrl"), query.join("&")].join("?")
|
let authorizationUrl = schema.get("authorizationUrl")
|
||||||
|
let url = [authorizationUrl, query.join("&")].join(authorizationUrl.indexOf("?") === -1 ? "?" : "&")
|
||||||
|
|
||||||
// pass action authorizeOauth2 and authentication data through window
|
// pass action authorizeOauth2 and authentication data through window
|
||||||
// to authorize with oauth2
|
// to authorize with oauth2
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default {
|
|||||||
securities.entrySeq().forEach( ([ key, security ]) => {
|
securities.entrySeq().forEach( ([ key, security ]) => {
|
||||||
let type = security.getIn(["schema", "type"])
|
let type = security.getIn(["schema", "type"])
|
||||||
|
|
||||||
if ( type === "apiKey" ) {
|
if ( type === "apiKey" || type === "http" ) {
|
||||||
map = map.set(key, security)
|
map = map.set(key, security)
|
||||||
} else if ( type === "basic" ) {
|
} else if ( type === "basic" ) {
|
||||||
let username = security.getIn(["value", "username"])
|
let username = security.getIn(["value", "username"])
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const shownDefinitions = createSelector(
|
|||||||
|
|
||||||
export const definitionsToAuthorize = createSelector(
|
export const definitionsToAuthorize = createSelector(
|
||||||
state,
|
state,
|
||||||
() =>( { specSelectors } ) => {
|
() => ( { specSelectors } ) => {
|
||||||
let definitions = specSelectors.securityDefinitions()
|
let definitions = specSelectors.securityDefinitions()
|
||||||
let list = List()
|
let list = List()
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ export const definitionsToAuthorize = createSelector(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
export const getDefinitionsByNames = ( state, securities ) =>( { specSelectors } ) => {
|
export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors } ) => {
|
||||||
let securityDefinitions = specSelectors.securityDefinitions()
|
let securityDefinitions = specSelectors.securityDefinitions()
|
||||||
let result = List()
|
let result = List()
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export const authorized = createSelector(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
export const isAuthorized = ( state, securities ) =>( { authSelectors } ) => {
|
export const isAuthorized = ( state, securities ) => ( { authSelectors } ) => {
|
||||||
let authorized = authSelectors.authorized()
|
let authorized = authSelectors.authorized()
|
||||||
|
|
||||||
if(!List.isList(securities)) {
|
if(!List.isList(securities)) {
|
||||||
|
|||||||
@@ -7,13 +7,16 @@ export default function downloadUrlPlugin (toolbox) {
|
|||||||
let { fn } = toolbox
|
let { fn } = toolbox
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
download: (url)=> ({ errActions, specSelectors, specActions }) => {
|
download: (url)=> ({ errActions, specSelectors, specActions, getConfigs }) => {
|
||||||
let { fetch } = fn
|
let { fetch } = fn
|
||||||
|
const config = getConfigs()
|
||||||
url = url || specSelectors.url()
|
url = url || specSelectors.url()
|
||||||
specActions.updateLoadingStatus("loading")
|
specActions.updateLoadingStatus("loading")
|
||||||
fetch({
|
fetch({
|
||||||
url,
|
url,
|
||||||
loadSpec: true,
|
loadSpec: true,
|
||||||
|
requestInterceptor: config.requestInterceptor || (a => a),
|
||||||
|
responseInterceptor: config.responseInterceptor || (a => a),
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json,*/*"
|
"Accept": "application/json,*/*"
|
||||||
|
|||||||
60
src/core/plugins/oas3/auth-extensions/wrap-selectors.js
Normal file
60
src/core/plugins/oas3/auth-extensions/wrap-selectors.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { createSelector } from "reselect"
|
||||||
|
import { List, Map, fromJS } from "immutable"
|
||||||
|
import { isOAS3 as isOAS3Helper } from "../helpers"
|
||||||
|
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
const state = state => state
|
||||||
|
|
||||||
|
function onlyOAS3(selector) {
|
||||||
|
return (ori, system) => (state, ...args) => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
if(isOAS3Helper(spec)) {
|
||||||
|
return selector(system, ...args)
|
||||||
|
} else {
|
||||||
|
return ori(...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const definitionsToAuthorize = onlyOAS3(createSelector(
|
||||||
|
state,
|
||||||
|
({ specSelectors }) => {
|
||||||
|
// Coerce our OpenAPI 3.0 definitions into monoflow definitions
|
||||||
|
// that look like Swagger2 definitions.
|
||||||
|
let definitions = specSelectors.securityDefinitions()
|
||||||
|
let list = List()
|
||||||
|
|
||||||
|
definitions.entrySeq().forEach( ([ defName, definition ]) => {
|
||||||
|
const type = definition.get("type")
|
||||||
|
|
||||||
|
if(type === "oauth2") {
|
||||||
|
definition.get("flows").entrySeq().forEach(([flowKey, flowVal]) => {
|
||||||
|
let translatedDef = fromJS({
|
||||||
|
flow: flowKey,
|
||||||
|
authorizationUrl: flowVal.get("authorizationUrl"),
|
||||||
|
tokenUrl: flowVal.get("tokenUrl"),
|
||||||
|
scopes: flowVal.get("scopes"),
|
||||||
|
type: definition.get("type")
|
||||||
|
})
|
||||||
|
|
||||||
|
list = list.push(new Map({
|
||||||
|
[defName]: translatedDef.filter((v) => {
|
||||||
|
// filter out unset values, sometimes `authorizationUrl`
|
||||||
|
// and `tokenUrl` come out as `undefined` in the data
|
||||||
|
return v !== undefined
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(type === "http" || type === "apiKey") {
|
||||||
|
list = list.push(new Map({
|
||||||
|
[defName]: definition
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
))
|
||||||
134
src/core/plugins/oas3/components/http-auth.jsx
Normal file
134
src/core/plugins/oas3/components/http-auth.jsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
|
export default class HttpAuth extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
authorized: PropTypes.object,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
errSelectors: PropTypes.object.isRequired,
|
||||||
|
schema: PropTypes.object.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context)
|
||||||
|
let { name, schema } = this.props
|
||||||
|
let value = this.getValue()
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
name: name,
|
||||||
|
schema: schema,
|
||||||
|
value: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue () {
|
||||||
|
let { name, authorized } = this.props
|
||||||
|
|
||||||
|
return authorized && authorized.getIn([name, "value"])
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange =(e) => {
|
||||||
|
let { onChange } = this.props
|
||||||
|
let { value, name } = e.target
|
||||||
|
|
||||||
|
let newValue = this.state.value || {}
|
||||||
|
if(name) {
|
||||||
|
newValue[name] = value
|
||||||
|
} else {
|
||||||
|
newValue = value
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ value: newValue }, () => onChange(this.state))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { schema, getComponent, errSelectors, name } = this.props
|
||||||
|
const Input = getComponent("Input")
|
||||||
|
const Row = getComponent("Row")
|
||||||
|
const Col = getComponent("Col")
|
||||||
|
const AuthError = getComponent("authError")
|
||||||
|
const Markdown = getComponent( "Markdown" )
|
||||||
|
const JumpToPath = getComponent("JumpToPath", true)
|
||||||
|
|
||||||
|
const scheme = schema.get("scheme")
|
||||||
|
let value = this.getValue()
|
||||||
|
let errors = errSelectors.allErrors().filter( err => err.get("authId") === name)
|
||||||
|
|
||||||
|
if(scheme === "basic") {
|
||||||
|
let username = value ? value.get("username") : null
|
||||||
|
return <div>
|
||||||
|
<h4>
|
||||||
|
<code>{ name || schema.get("name") }</code>
|
||||||
|
(http, Basic)
|
||||||
|
<JumpToPath path={[ "securityDefinitions", name ]} />
|
||||||
|
</h4>
|
||||||
|
{ username && <h6>Authorized</h6> }
|
||||||
|
<Row>
|
||||||
|
<Markdown source={ schema.get("description") } />
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<label>Username:</label>
|
||||||
|
{
|
||||||
|
username ? <code> { username } </code>
|
||||||
|
: <Col><Input type="text" required="required" name="username" onChange={ this.onChange }/></Col>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<label>Password:</label>
|
||||||
|
{
|
||||||
|
username ? <code> ****** </code>
|
||||||
|
: <Col><Input required="required"
|
||||||
|
autoComplete="new-password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
onChange={ this.onChange }/></Col>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
{
|
||||||
|
errors.valueSeq().map( (error, key) => {
|
||||||
|
return <AuthError error={ error }
|
||||||
|
key={ key }/>
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scheme === "bearer") {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>
|
||||||
|
<code>{ name || schema.get("name") }</code>
|
||||||
|
(http, Bearer)
|
||||||
|
<JumpToPath path={[ "securityDefinitions", name ]} />
|
||||||
|
</h4>
|
||||||
|
{ value && <h6>Authorized</h6>}
|
||||||
|
<Row>
|
||||||
|
<Markdown source={ schema.get("description") } />
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<p>In: <code>{ schema.get("in") }</code></p>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<label>Value:</label>
|
||||||
|
{
|
||||||
|
value ? <code> ****** </code>
|
||||||
|
: <Col><Input type="text" onChange={ this.onChange }/></Col>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
{
|
||||||
|
errors.valueSeq().map( (error, key) => {
|
||||||
|
return <AuthError error={ error }
|
||||||
|
key={ key }/>
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <div>
|
||||||
|
<em><b>{name}</b> HTTP authentication: unsupported or missing scheme</em>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,9 +3,11 @@ import RequestBody from "./request-body"
|
|||||||
import OperationLink from "./operation-link.jsx"
|
import OperationLink from "./operation-link.jsx"
|
||||||
import Servers from "./servers"
|
import Servers from "./servers"
|
||||||
import RequestBodyEditor from "./request-body-editor"
|
import RequestBodyEditor from "./request-body-editor"
|
||||||
|
import HttpAuth from "./http-auth"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Callbacks,
|
Callbacks,
|
||||||
|
HttpAuth,
|
||||||
RequestBody,
|
RequestBody,
|
||||||
Servers,
|
Servers,
|
||||||
RequestBodyEditor,
|
RequestBodyEditor,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { OrderedMap } from "immutable"
|
|||||||
const RequestBody = ({
|
const RequestBody = ({
|
||||||
requestBody,
|
requestBody,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
contentType,
|
contentType,
|
||||||
isExecute,
|
isExecute,
|
||||||
@@ -27,6 +28,7 @@ const RequestBody = ({
|
|||||||
}
|
}
|
||||||
<ModelExample
|
<ModelExample
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
expandDepth={1}
|
expandDepth={1}
|
||||||
isExecute={isExecute}
|
isExecute={isExecute}
|
||||||
@@ -46,6 +48,7 @@ const RequestBody = ({
|
|||||||
RequestBody.propTypes = {
|
RequestBody.propTypes = {
|
||||||
requestBody: ImPropTypes.orderedMap.isRequired,
|
requestBody: ImPropTypes.orderedMap.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
contentType: PropTypes.string.isRequired,
|
contentType: PropTypes.string.isRequired,
|
||||||
isExecute: PropTypes.bool.isRequired,
|
isExecute: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// import reducers from "./reducers"
|
// import reducers from "./reducers"
|
||||||
// import * as actions from "./actions"
|
// import * as actions from "./actions"
|
||||||
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
||||||
|
import * as authWrapSelectors from "./auth-extensions/wrap-selectors"
|
||||||
import * as specSelectors from "./spec-extensions/selectors"
|
import * as specSelectors from "./spec-extensions/selectors"
|
||||||
import components from "./components"
|
import components from "./components"
|
||||||
import wrapComponents from "./wrap-components"
|
import wrapComponents from "./wrap-components"
|
||||||
@@ -17,6 +18,9 @@ export default function() {
|
|||||||
wrapSelectors: specWrapSelectors,
|
wrapSelectors: specWrapSelectors,
|
||||||
selectors: specSelectors
|
selectors: specSelectors
|
||||||
},
|
},
|
||||||
|
auth: {
|
||||||
|
wrapSelectors: authWrapSelectors
|
||||||
|
},
|
||||||
oas3: {
|
oas3: {
|
||||||
actions: oas3Actions,
|
actions: oas3Actions,
|
||||||
reducers: oas3Reducers,
|
reducers: oas3Reducers,
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ export const definitions = onlyOAS3(createSelector(
|
|||||||
spec => spec.getIn(["components", "schemas"]) || Map()
|
spec => spec.getIn(["components", "schemas"]) || Map()
|
||||||
))
|
))
|
||||||
|
|
||||||
|
export const securityDefinitions = onlyOAS3(createSelector(
|
||||||
|
spec,
|
||||||
|
spec => spec.getIn(["components", "securitySchemes"]) || Map()
|
||||||
|
))
|
||||||
|
|
||||||
export const host = OAS3NullSelector
|
export const host = OAS3NullSelector
|
||||||
export const basePath = OAS3NullSelector
|
export const basePath = OAS3NullSelector
|
||||||
export const consumes = OAS3NullSelector
|
export const consumes = OAS3NullSelector
|
||||||
|
|||||||
23
src/core/plugins/oas3/wrap-components/auth-item.jsx
Normal file
23
src/core/plugins/oas3/wrap-components/auth-item.jsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(({ Ori, ...props }) => {
|
||||||
|
const {
|
||||||
|
schema, getComponent, errSelectors, authorized, onAuthChange, name
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const HttpAuth = getComponent("HttpAuth")
|
||||||
|
const type = schema.get("type")
|
||||||
|
|
||||||
|
if(type === "http") {
|
||||||
|
return <HttpAuth key={ name }
|
||||||
|
schema={ schema }
|
||||||
|
name={ name }
|
||||||
|
errSelectors={ errSelectors }
|
||||||
|
authorized={ authorized }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
onChange={ onAuthChange }/>
|
||||||
|
} else {
|
||||||
|
return <Ori {...props} />
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import Markdown from "./markdown"
|
import Markdown from "./markdown"
|
||||||
|
import AuthItem from "./auth-item"
|
||||||
import parameters from "./parameters"
|
import parameters from "./parameters"
|
||||||
import VersionStamp from "./version-stamp"
|
import VersionStamp from "./version-stamp"
|
||||||
import OnlineValidatorBadge from "./online-validator-badge"
|
import OnlineValidatorBadge from "./online-validator-badge"
|
||||||
@@ -6,6 +7,7 @@ import Model from "./model"
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
Markdown,
|
Markdown,
|
||||||
|
AuthItem,
|
||||||
parameters,
|
parameters,
|
||||||
VersionStamp,
|
VersionStamp,
|
||||||
model: Model,
|
model: Model,
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
import ReactMarkdown from "react-markdown"
|
import ReactMarkdown from "react-markdown"
|
||||||
|
import { Parser, HtmlRenderer } from "commonmark"
|
||||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
import { sanitizer } from "core/components/providers/markdown"
|
import { sanitizer } from "core/components/providers/markdown"
|
||||||
|
|
||||||
export default OAS3ComponentWrapFactory(({ source }) => { return source ? (
|
export const Markdown = ({ source }) => {
|
||||||
|
if ( source ) {
|
||||||
|
const parser = new Parser()
|
||||||
|
const writer = new HtmlRenderer()
|
||||||
|
const html = writer.render(parser.parse(source || ""))
|
||||||
|
const sanitized = sanitizer(html)
|
||||||
|
|
||||||
|
if ( !source || !html || !sanitized ) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
source={sanitizer(source)}
|
source={sanitized}
|
||||||
className={"renderedMarkdown"}
|
className={"renderedMarkdown"}
|
||||||
/>
|
/>
|
||||||
) : null})
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
Markdown.propTypes = {
|
||||||
|
source: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(Markdown)
|
||||||
@@ -49,7 +49,7 @@ class Parameters extends Component {
|
|||||||
onChangeKey,
|
onChangeKey,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
changeParam( onChangeKey, param.get("name"), value, isXml)
|
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeConsumesWrapper = ( val ) => {
|
onChangeConsumesWrapper = ( val ) => {
|
||||||
|
|||||||
@@ -130,17 +130,20 @@ export const formatIntoYaml = () => ({specActions, specSelectors}) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeParam( path, paramName, value, isXml ){
|
export function changeParam( path, paramName, paramIn, value, isXml ){
|
||||||
return {
|
return {
|
||||||
type: UPDATE_PARAM,
|
type: UPDATE_PARAM,
|
||||||
payload:{ path, value, paramName, isXml }
|
payload:{ path, value, paramName, paramIn, isXml }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateParams( payload ){
|
export const validateParams = ( payload, isOAS3 ) =>{
|
||||||
return {
|
return {
|
||||||
type: VALIDATE_PARAMS,
|
type: VALIDATE_PARAMS,
|
||||||
payload:{ pathMethod: payload }
|
payload:{
|
||||||
|
pathMethod: payload,
|
||||||
|
isOAS3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +209,6 @@ export const executeRequest = (req) =>
|
|||||||
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
|
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
|
||||||
req.contextUrl = parseUrl(specSelectors.url()).toString()
|
req.contextUrl = parseUrl(specSelectors.url()).toString()
|
||||||
|
|
||||||
|
|
||||||
if(op && op.operationId) {
|
if(op && op.operationId) {
|
||||||
req.operationId = op.operationId
|
req.operationId = op.operationId
|
||||||
} else if(op && pathName && method) {
|
} else if(op && pathName && method) {
|
||||||
|
|||||||
@@ -40,9 +40,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[UPDATE_PARAM]: ( state, {payload} ) => {
|
[UPDATE_PARAM]: ( state, {payload} ) => {
|
||||||
let { path, paramName, value, isXml } = payload
|
let { path, paramName, paramIn, value, isXml } = payload
|
||||||
|
|
||||||
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
|
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
|
||||||
const index = parameters.findIndex(p => p.get( "name" ) === paramName )
|
const index = parameters.findIndex(p => p.get( "name" ) === paramName && p.get("in") === paramIn )
|
||||||
if (!(value instanceof win.File)) {
|
if (!(value instanceof win.File)) {
|
||||||
value = fromJSOrdered( value )
|
value = fromJSOrdered( value )
|
||||||
}
|
}
|
||||||
@@ -50,14 +51,14 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod } } ) => {
|
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
|
||||||
let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] )
|
let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] )
|
||||||
let isXml = /xml/i.test(operation.get("consumes_value"))
|
let isXml = /xml/i.test(operation.get("consumes_value"))
|
||||||
|
|
||||||
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
|
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
|
||||||
return parameters.withMutations( parameters => {
|
return parameters.withMutations( parameters => {
|
||||||
for ( let i = 0, len = parameters.count(); i < len; i++ ) {
|
for ( let i = 0, len = parameters.count(); i < len; i++ ) {
|
||||||
let errors = validateParam(parameters.get(i), isXml)
|
let errors = validateParam(parameters.get(i), isXml, isOAS3)
|
||||||
parameters.setIn([i, "errors"], fromJS(errors))
|
parameters.setIn([i, "errors"], fromJS(errors))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -260,10 +260,10 @@ export const allowTryItOutFor = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the parameter value by parameter name
|
// Get the parameter value by parameter name
|
||||||
export function getParameter(state, pathMethod, name) {
|
export function getParameter(state, pathMethod, name, inType) {
|
||||||
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
||||||
return params.filter( (p) => {
|
return params.filter( (p) => {
|
||||||
return Map.isMap(p) && p.get("name") === name
|
return Map.isMap(p) && p.get("name") === name && p.get("in") === inType
|
||||||
}).first()
|
}).first()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ export function parameterValues(state, pathMethod, isXml) {
|
|||||||
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
||||||
return params.reduce( (hash, p) => {
|
return params.reduce( (hash, p) => {
|
||||||
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
||||||
return hash.set(p.get("name"), value)
|
return hash.set(`${p.get("in")}.${p.get("name")}`, value)
|
||||||
}, fromJS({}))
|
}, fromJS({}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,3 +13,7 @@ export const executeRequest = (ori, { specActions }) => (req) => {
|
|||||||
specActions.logRequest(req)
|
specActions.logRequest(req)
|
||||||
return ori(req)
|
return ori(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateParams = (ori, { specSelectors }) => (req) => {
|
||||||
|
return ori(req, specSelectors.isOAS3())
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import AuthorizationPopup from "core/components/auth/authorization-popup"
|
|||||||
import AuthorizeBtn from "core/components/auth/authorize-btn"
|
import AuthorizeBtn from "core/components/auth/authorize-btn"
|
||||||
import AuthorizeOperationBtn from "core/components/auth/authorize-operation-btn"
|
import AuthorizeOperationBtn from "core/components/auth/authorize-operation-btn"
|
||||||
import Auths from "core/components/auth/auths"
|
import Auths from "core/components/auth/auths"
|
||||||
|
import AuthItem from "core/components/auth/auth-item"
|
||||||
import AuthError from "core/components/auth/error"
|
import AuthError from "core/components/auth/error"
|
||||||
import ApiKeyAuth from "core/components/auth/api-key-auth"
|
import ApiKeyAuth from "core/components/auth/api-key-auth"
|
||||||
import BasicAuth from "core/components/auth/basic-auth"
|
import BasicAuth from "core/components/auth/basic-auth"
|
||||||
@@ -70,6 +71,7 @@ export default function() {
|
|||||||
authorizeBtn: AuthorizeBtn,
|
authorizeBtn: AuthorizeBtn,
|
||||||
authorizeOperationBtn: AuthorizeOperationBtn,
|
authorizeOperationBtn: AuthorizeOperationBtn,
|
||||||
auths: Auths,
|
auths: Auths,
|
||||||
|
AuthItem: AuthItem,
|
||||||
authError: AuthError,
|
authError: AuthError,
|
||||||
oauth2: Oauth2,
|
oauth2: Oauth2,
|
||||||
apiKeyAuth: ApiKeyAuth,
|
apiKeyAuth: ApiKeyAuth,
|
||||||
|
|||||||
@@ -470,6 +470,18 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|
|||||||
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
|
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateMaximum = ( val, max ) => {
|
||||||
|
if (val > max) {
|
||||||
|
return "Value must be less than Maximum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMinimum = ( val, min ) => {
|
||||||
|
if (val < min) {
|
||||||
|
return "Value must be greater than Minimum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const validateNumber = ( val ) => {
|
export const validateNumber = ( val ) => {
|
||||||
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
||||||
return "Value must be a number"
|
return "Value must be a number"
|
||||||
@@ -500,12 +512,43 @@ export const validateString = ( val ) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateDateTime = (val) => {
|
||||||
|
if (isNaN(Date.parse(val))) {
|
||||||
|
return "Value must be a DateTime"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateGuid = (val) => {
|
||||||
|
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
|
||||||
|
return "Value must be a Guid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMaxLength = (val, max) => {
|
||||||
|
if (val.length > max) {
|
||||||
|
return "Value must be less than MaxLength"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMinLength = (val, min) => {
|
||||||
|
if (val.length < min) {
|
||||||
|
return "Value must be greater than MinLength"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validation of parameters before execute
|
// validation of parameters before execute
|
||||||
export const validateParam = (param, isXml) => {
|
export const validateParam = (param, isXml, isOAS3 = false) => {
|
||||||
let errors = []
|
let errors = []
|
||||||
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
let type = param.get("type")
|
|
||||||
|
let paramDetails = isOAS3 ? param.get("schema") : param
|
||||||
|
let maximum = paramDetails.get("maximum")
|
||||||
|
let minimum = paramDetails.get("minimum")
|
||||||
|
let type = paramDetails.get("type")
|
||||||
|
let format = paramDetails.get("format")
|
||||||
|
let maxLength = paramDetails.get("maxLength")
|
||||||
|
let minLength = paramDetails.get("minLength")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
||||||
@@ -522,13 +565,40 @@ export const validateParam = (param, isXml) => {
|
|||||||
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
||||||
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
||||||
|
|
||||||
|
if (maxLength || maxLength === 0) {
|
||||||
|
let err = validateMaxLength(value, maxLength)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minLength) {
|
||||||
|
let err = validateMinLength(value, minLength)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
||||||
errors.push("Required field is not provided")
|
errors.push("Required field is not provided")
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maximum || maximum === 0) {
|
||||||
|
let err = validateMaximum(value, maximum)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minimum || minimum === 0) {
|
||||||
|
let err = validateMinimum(value, minimum)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
if ( type === "string" ) {
|
if ( type === "string" ) {
|
||||||
let err = validateString(value)
|
let err
|
||||||
|
if (format === "date-time") {
|
||||||
|
err = validateDateTime(value)
|
||||||
|
} else if (format === "uuid") {
|
||||||
|
err = validateGuid(value)
|
||||||
|
} else {
|
||||||
|
err = validateString(value)
|
||||||
|
}
|
||||||
if (!err) return errors
|
if (!err) return errors
|
||||||
errors.push(err)
|
errors.push(err)
|
||||||
} else if ( type === "boolean" ) {
|
} else if ( type === "boolean" ) {
|
||||||
@@ -548,7 +618,7 @@ export const validateParam = (param, isXml) => {
|
|||||||
|
|
||||||
if ( !value.count() ) { return errors }
|
if ( !value.count() ) { return errors }
|
||||||
|
|
||||||
itemType = param.getIn(["items", "type"])
|
itemType = paramDetails.getIn(["items", "type"])
|
||||||
|
|
||||||
value.forEach((item, index) => {
|
value.forEach((item, index) => {
|
||||||
let err
|
let err
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ select
|
|||||||
.opblock-body select
|
.opblock-body select
|
||||||
{
|
{
|
||||||
min-width: 230px;
|
min-width: 230px;
|
||||||
|
@media (max-width: 768px)
|
||||||
|
{
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label
|
label
|
||||||
@@ -56,6 +60,10 @@ input[type=file]
|
|||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
max-width: 175px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
&.invalid
|
&.invalid
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -250,10 +250,17 @@
|
|||||||
.opblock-summary-path__deprecated
|
.opblock-summary-path__deprecated
|
||||||
{
|
{
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 3 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|
||||||
@include text_code();
|
@include text_code();
|
||||||
@@ -540,14 +547,14 @@
|
|||||||
|
|
||||||
.response-col_description__inner
|
.response-col_description__inner
|
||||||
{
|
{
|
||||||
span
|
div.markdown, div.renderedMarkdown
|
||||||
{
|
{
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
margin: 10px 0;
|
margin: 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -765,14 +772,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.renderedMarkdown {
|
|
||||||
p {
|
|
||||||
@include text_body();
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.response-content-type {
|
.response-content-type {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
|
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ span
|
|||||||
.prop-name
|
.prop-name
|
||||||
{
|
{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100px;
|
margin-right: 1em;
|
||||||
|
width: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prop-type
|
.prop-type
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.topbar
|
.topbar
|
||||||
{
|
{
|
||||||
padding: 8px 30px;
|
padding: 8px 0;
|
||||||
|
|
||||||
background-color: #89bf04;
|
background-color: #89bf04;
|
||||||
.topbar-wrapper
|
.topbar-wrapper
|
||||||
@@ -39,7 +39,6 @@
|
|||||||
input[type=text]
|
input[type=text]
|
||||||
{
|
{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 350px;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
border: 2px solid #547f00;
|
border: 2px solid #547f00;
|
||||||
@@ -84,7 +83,7 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
padding: 4px 40px;
|
padding: 4px 30px;
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
|
|||||||
54
test/components/markdown.js
Normal file
54
test/components/markdown.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { render } from "enzyme"
|
||||||
|
import Markdown from "components/providers/markdown"
|
||||||
|
import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.js"
|
||||||
|
|
||||||
|
describe("Markdown component", function() {
|
||||||
|
describe("Swagger 2.0", function() {
|
||||||
|
it("allows image elements", function() {
|
||||||
|
const str = ``
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p><img src="http://image.source" title="Image title"></p>\n</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("allows heading elements", function() {
|
||||||
|
const str = `
|
||||||
|
# h1
|
||||||
|
## h2
|
||||||
|
### h3
|
||||||
|
#### h4
|
||||||
|
##### h5
|
||||||
|
###### h6`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><h1>h1</h1>\n<h2>h2</h2>\n<h3>h3</h3>\n<h4>h4</h4>\n<h5>h5</h5>\n<h6>h6</h6>\n</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("allows links", function() {
|
||||||
|
const str = `[Link](https://example.com/)`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p><a href="https://example.com/" target="_blank">Link</a></p>\n</div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("OAS 3", function() {
|
||||||
|
it("allows image elements", function() {
|
||||||
|
const str = ``
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="http://image.source" title="Image title"></p></div></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("allows heading elements", function() {
|
||||||
|
const str = `
|
||||||
|
# h1
|
||||||
|
## h2
|
||||||
|
### h3
|
||||||
|
#### h4
|
||||||
|
##### h5
|
||||||
|
###### h6`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><h1>h1</h1>\n<h2>h2</h2>\n<h3>h3</h3>\n<h4>h4</h4>\n<h5>h5</h5>\n<h6>h6</h6></div></div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
116
test/components/model-example.js
Normal file
116
test/components/model-example.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import ModelExample from "components/model-example"
|
||||||
|
import ModelComponent from "components/model-wrapper"
|
||||||
|
|
||||||
|
describe("<ModelExample/>", function(){
|
||||||
|
// Given
|
||||||
|
let components = {
|
||||||
|
ModelWrapper: ModelComponent
|
||||||
|
}
|
||||||
|
let props = {
|
||||||
|
getComponent: (c) => {
|
||||||
|
return components[c]
|
||||||
|
},
|
||||||
|
specSelectors: {},
|
||||||
|
schema: {},
|
||||||
|
example: "{\"example\": \"value\"}",
|
||||||
|
isExecute: false,
|
||||||
|
getConfigs: () => ({
|
||||||
|
defaultModelRendering: "model",
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let exampleSelectedTestInputs = [
|
||||||
|
{ defaultModelRendering: "model", isExecute: true },
|
||||||
|
{ defaultModelRendering: "example", isExecute: true },
|
||||||
|
{ defaultModelRendering: "example", isExecute: false },
|
||||||
|
{ defaultModelRendering: "othervalue", isExecute: true },
|
||||||
|
{ defaultModelRendering: "othervalue", isExecute: false }
|
||||||
|
]
|
||||||
|
let modelSelectedTestInputs = [
|
||||||
|
{ defaultModelRendering: "model", isExecute: false }
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
it("renders model and example tabs", function(){
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then should render tabs
|
||||||
|
expect(wrapper.find("div > ul.tab").length).toEqual(1)
|
||||||
|
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
expect(tabs.length).toEqual(2)
|
||||||
|
tabs.forEach((node) => {
|
||||||
|
expect(node.length).toEqual(1)
|
||||||
|
expect(node.name()).toEqual("li")
|
||||||
|
expect(node.hasClass("tabitem")).toEqual(true)
|
||||||
|
})
|
||||||
|
expect(tabs.at(0).text()).toEqual("Example Value")
|
||||||
|
expect(tabs.at(1).text()).toEqual("Model")
|
||||||
|
})
|
||||||
|
|
||||||
|
exampleSelectedTestInputs.forEach(function(testInputs) {
|
||||||
|
it("example tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||||
|
// When
|
||||||
|
props.isExecute = testInputs.isExecute
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: testInputs.defaultModelRendering,
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
|
||||||
|
let exampleTab = tabs.at(0)
|
||||||
|
expect(exampleTab.hasClass("active")).toEqual(true)
|
||||||
|
let modelTab = tabs.at(1)
|
||||||
|
expect(modelTab.hasClass("active")).toEqual(false)
|
||||||
|
|
||||||
|
expect(wrapper.find("div > div").length).toEqual(1)
|
||||||
|
expect(wrapper.find("div > div").text()).toEqual(props.example)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
modelSelectedTestInputs.forEach(function(testInputs) {
|
||||||
|
it("model tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||||
|
// When
|
||||||
|
props.isExecute = testInputs.isExecute
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: testInputs.defaultModelRendering,
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
|
||||||
|
let exampleTab = tabs.at(0)
|
||||||
|
expect(exampleTab.hasClass("active")).toEqual(false)
|
||||||
|
let modelTab = tabs.at(1)
|
||||||
|
expect(modelTab.hasClass("active")).toEqual(true)
|
||||||
|
|
||||||
|
expect(wrapper.find("div > div").length).toEqual(1)
|
||||||
|
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("passes defaultModelExpandDepth to ModelComponent", function(){
|
||||||
|
// When
|
||||||
|
let expandDepth = 0
|
||||||
|
props.isExecute = false
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: "model",
|
||||||
|
defaultModelExpandDepth: expandDepth
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(expandDepth)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
51
test/components/models.js
Normal file
51
test/components/models.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import Models from "components/models"
|
||||||
|
import ModelCollpase from "components/model-collapse"
|
||||||
|
import ModelComponent from "components/model-wrapper"
|
||||||
|
|
||||||
|
describe("<Models/>", function(){
|
||||||
|
// Given
|
||||||
|
let components = {
|
||||||
|
Collapse: ModelCollpase,
|
||||||
|
ModelWrapper: ModelComponent
|
||||||
|
}
|
||||||
|
let props = {
|
||||||
|
getComponent: (c) => {
|
||||||
|
return components[c]
|
||||||
|
},
|
||||||
|
specSelectors: {
|
||||||
|
definitions: function() {
|
||||||
|
return fromJS({
|
||||||
|
def1: {},
|
||||||
|
def2: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layoutSelectors: {
|
||||||
|
isShown: createSpy()
|
||||||
|
},
|
||||||
|
layoutActions: {},
|
||||||
|
getConfigs: () => ({
|
||||||
|
docExpansion: "list",
|
||||||
|
defaultModelExpandDepth: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it("passes defaultModelExpandDepth to ModelWrapper", function(){
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<Models {...props}/>)
|
||||||
|
|
||||||
|
// Then should render tabs
|
||||||
|
expect(wrapper.find("ModelCollapse").length).toEqual(1)
|
||||||
|
expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0)
|
||||||
|
wrapper.find("ModelComponent").forEach((modelWrapper) => {
|
||||||
|
expect(modelWrapper.props().expandDepth).toBe(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
49
test/components/primitive-model.js
Normal file
49
test/components/primitive-model.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import PrimitiveModel from "components/primitive-model"
|
||||||
|
|
||||||
|
describe("<PrimitiveModel/>", function() {
|
||||||
|
describe("Model name", function() {
|
||||||
|
const dummyComponent = () => null
|
||||||
|
const components = {
|
||||||
|
Markdown: dummyComponent,
|
||||||
|
EnumModel: dummyComponent
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
getComponent: c => components[c],
|
||||||
|
name: "Name from props",
|
||||||
|
depth: 1,
|
||||||
|
schema: fromJS({
|
||||||
|
type: "string",
|
||||||
|
title: "Custom model title"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it("renders the schema's title", function() {
|
||||||
|
// When
|
||||||
|
const wrapper = shallow(<PrimitiveModel {...props}/>)
|
||||||
|
const modelTitleEl = wrapper.find("span.model-title")
|
||||||
|
expect(modelTitleEl.length).toEqual(1)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect( modelTitleEl.text() ).toEqual( "Custom model title" )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("falls back to the passed-in `name` prop for the title", function() {
|
||||||
|
// When
|
||||||
|
props.schema = fromJS({
|
||||||
|
type: "string"
|
||||||
|
})
|
||||||
|
const wrapper = shallow(<PrimitiveModel {...props}/>)
|
||||||
|
const modelTitleEl = wrapper.find("span.model-title")
|
||||||
|
expect(modelTitleEl.length).toEqual(1)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect( modelTitleEl.text() ).toEqual( "Name from props" )
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
} )
|
||||||
39
test/core/oauth2-authorize.js
Normal file
39
test/core/oauth2-authorize.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import win from "core/window"
|
||||||
|
import oauth2Authorize from "core/oauth2-authorize"
|
||||||
|
|
||||||
|
describe("oauth2", function () {
|
||||||
|
|
||||||
|
let mockSchema = {
|
||||||
|
flow: "accessCode",
|
||||||
|
authorizationUrl: "https://testAuthorizationUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
let authConfig = {
|
||||||
|
auth: { schema: { get: (key)=> mockSchema[key] } },
|
||||||
|
authActions: {},
|
||||||
|
errActions: {},
|
||||||
|
configs: { oauth2RedirectUrl: "" },
|
||||||
|
authConfigs: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("authorize redirect", function () {
|
||||||
|
|
||||||
|
it("should build authorize url", function() {
|
||||||
|
win.open = createSpy()
|
||||||
|
oauth2Authorize(authConfig)
|
||||||
|
expect(win.open.calls.length).toEqual(1)
|
||||||
|
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&state=")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should append query paramters to authorizeUrl with query parameters", function() {
|
||||||
|
win.open = createSpy()
|
||||||
|
mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1"
|
||||||
|
oauth2Authorize(authConfig)
|
||||||
|
expect(win.open.calls.length).toEqual(1)
|
||||||
|
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&state=")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
116
test/core/plugins/oas3/wrap-auth-selectors.js
Normal file
116
test/core/plugins/oas3/wrap-auth-selectors.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { Map, fromJS } from "immutable"
|
||||||
|
import {
|
||||||
|
definitionsToAuthorize
|
||||||
|
} from "corePlugins/oas3/auth-extensions/wrap-selectors"
|
||||||
|
|
||||||
|
describe("oas3 plugin - auth extensions - wrapSelectors", function(){
|
||||||
|
|
||||||
|
describe("execute", function(){
|
||||||
|
|
||||||
|
it("should add `securities` to the oriAction call", function(){
|
||||||
|
// Given
|
||||||
|
const system = {
|
||||||
|
getSystem: () => system,
|
||||||
|
specSelectors: {
|
||||||
|
specJson: () => fromJS({
|
||||||
|
openapi: "3.0.0"
|
||||||
|
}),
|
||||||
|
securityDefinitions: () => {
|
||||||
|
return fromJS({
|
||||||
|
"oauth2AuthorizationCode": {
|
||||||
|
"type": "oauth2",
|
||||||
|
"flows": {
|
||||||
|
"authorizationCode": {
|
||||||
|
"authorizationUrl": "http://google.com/",
|
||||||
|
"tokenUrl": "http://google.com/",
|
||||||
|
"scopes": {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth2Multiflow": {
|
||||||
|
"type": "oauth2",
|
||||||
|
"flows": {
|
||||||
|
"clientCredentials": {
|
||||||
|
"tokenUrl": "http://google.com/",
|
||||||
|
"scopes": {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"tokenUrl": "http://google.com/",
|
||||||
|
"scopes": {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authorizationCode": {
|
||||||
|
"authorizationUrl": "http://google.com/",
|
||||||
|
"tokenUrl": "http://google.com/",
|
||||||
|
"scopes": {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When
|
||||||
|
let res = definitionsToAuthorize(() => null, system)()
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(res.toJS()).toEqual([
|
||||||
|
{
|
||||||
|
oauth2AuthorizationCode: {
|
||||||
|
flow: "authorizationCode",
|
||||||
|
authorizationUrl: "http://google.com/",
|
||||||
|
tokenUrl: "http://google.com/",
|
||||||
|
scopes: {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
},
|
||||||
|
type: "oauth2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
oauth2Multiflow: {
|
||||||
|
flow: "clientCredentials",
|
||||||
|
tokenUrl: "http://google.com/",
|
||||||
|
scopes: {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
},
|
||||||
|
type: "oauth2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
oauth2Multiflow: {
|
||||||
|
flow: "password",
|
||||||
|
tokenUrl: "http://google.com/",
|
||||||
|
scopes: {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
},
|
||||||
|
type: "oauth2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
oauth2Multiflow: {
|
||||||
|
flow: "authorizationCode",
|
||||||
|
authorizationUrl: "http://google.com/",
|
||||||
|
tokenUrl: "http://google.com/",
|
||||||
|
scopes: {
|
||||||
|
"myScope": "our only scope"
|
||||||
|
},
|
||||||
|
type: "oauth2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@@ -29,8 +29,8 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/one": {
|
"/one": {
|
||||||
get: {
|
get: {
|
||||||
parameters: [
|
parameters: [
|
||||||
{ name: "one", value: 1},
|
{ name: "one", in: "query", value: 1},
|
||||||
{ name: "two", value: "duos"}
|
{ name: "two", in: "query", value: "duos"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,8 +43,8 @@ describe("spec plugin - selectors", function(){
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(paramValues.toJS()).toEqual({
|
expect(paramValues.toJS()).toEqual({
|
||||||
one: 1,
|
"query.one": 1,
|
||||||
two: "duos"
|
"query.two": "duos"
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
import expect from "expect"
|
import expect from "expect"
|
||||||
import { fromJS, OrderedMap } from "immutable"
|
import { fromJS, OrderedMap } from "immutable"
|
||||||
import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered, getAcceptControllingResponse, createDeepLinkPath, escapeDeepLinkPath } from "core/utils"
|
import {
|
||||||
|
mapToList,
|
||||||
|
validateMinLength,
|
||||||
|
validateMaxLength,
|
||||||
|
validateDateTime,
|
||||||
|
validateGuid,
|
||||||
|
validateNumber,
|
||||||
|
validateInteger,
|
||||||
|
validateParam,
|
||||||
|
validateFile,
|
||||||
|
validateMaximum,
|
||||||
|
validateMinimum,
|
||||||
|
fromJSOrdered,
|
||||||
|
getAcceptControllingResponse,
|
||||||
|
createDeepLinkPath,
|
||||||
|
escapeDeepLinkPath
|
||||||
|
} from "core/utils"
|
||||||
import win from "core/window"
|
import win from "core/window"
|
||||||
|
|
||||||
describe("utils", function() {
|
describe("utils", function() {
|
||||||
@@ -72,6 +88,36 @@ describe("utils", function() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("validateMaximum", function() {
|
||||||
|
let errorMessage = "Value must be less than Maximum"
|
||||||
|
|
||||||
|
it("doesn't return for valid input", function() {
|
||||||
|
expect(validateMaximum(9, 10)).toBeFalsy()
|
||||||
|
expect(validateMaximum(19, 20)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input", function() {
|
||||||
|
expect(validateMaximum(1, 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMaximum(10, 9)).toEqual(errorMessage)
|
||||||
|
expect(validateMaximum(20, 19)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMinimum", function() {
|
||||||
|
let errorMessage = "Value must be greater than Minimum"
|
||||||
|
|
||||||
|
it("doesn't return for valid input", function() {
|
||||||
|
expect(validateMinimum(2, 1)).toBeFalsy()
|
||||||
|
expect(validateMinimum(20, 10)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input", function() {
|
||||||
|
expect(validateMinimum(-1, 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMinimum(1, 2)).toEqual(errorMessage)
|
||||||
|
expect(validateMinimum(10, 20)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("validateNumber", function() {
|
describe("validateNumber", function() {
|
||||||
let errorMessage = "Value must be a number"
|
let errorMessage = "Value must be a number"
|
||||||
|
|
||||||
@@ -171,388 +217,498 @@ describe("utils", function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("validateDateTime", function() {
|
||||||
|
let errorMessage = "Value must be a DateTime"
|
||||||
|
|
||||||
|
it("doesn't return for valid dates", function() {
|
||||||
|
expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateDateTime(null)).toEqual(errorMessage)
|
||||||
|
expect(validateDateTime("string")).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateGuid", function() {
|
||||||
|
let errorMessage = "Value must be a Guid"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
|
||||||
|
expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateGuid(1)).toEqual(errorMessage)
|
||||||
|
expect(validateGuid("string")).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMaxLength", function() {
|
||||||
|
let errorMessage = "Value must be less than MaxLength"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateMaxLength("a", 1)).toBeFalsy()
|
||||||
|
expect(validateMaxLength("abc", 5)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateMaxLength("abc", 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMaxLength("abc", 1)).toEqual(errorMessage)
|
||||||
|
expect(validateMaxLength("abc", 2)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMinLength", function() {
|
||||||
|
let errorMessage = "Value must be greater than MinLength"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateMinLength("a", 1)).toBeFalsy()
|
||||||
|
expect(validateMinLength("abc", 2)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateMinLength("abc", 5)).toEqual(errorMessage)
|
||||||
|
expect(validateMinLength("abc", 8)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("validateParam", function() {
|
describe("validateParam", function() {
|
||||||
let param = null
|
let param = null
|
||||||
let result = null
|
let result = null
|
||||||
|
|
||||||
it("skips validation when `type` is not specified", function() {
|
const assertValidateParam = (param, expectedError) => {
|
||||||
// invalid type
|
// Swagger 2.0 version
|
||||||
|
result = validateParam( fromJS(param), false )
|
||||||
|
expect( result ).toEqual( expectedError )
|
||||||
|
|
||||||
|
// OAS3 version, using `schema` sub-object
|
||||||
|
let oas3Param = {
|
||||||
|
value: param.value,
|
||||||
|
required: param.required,
|
||||||
|
schema: {
|
||||||
|
...param,
|
||||||
|
value: undefined,
|
||||||
|
required: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = validateParam( fromJS(oas3Param), false, true )
|
||||||
|
expect( result ).toEqual( expectedError )
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should check the isOAS3 flag when validating parameters", function() {
|
||||||
|
// This should "skip" validation because there is no `schema.type` property
|
||||||
|
// and we are telling `validateParam` this is an OAS3 spec
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
value: "",
|
||||||
type: undefined,
|
required: true,
|
||||||
value: ""
|
schema: {
|
||||||
|
notTheTypeProperty: "string"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false, true )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required strings", function() {
|
it("validates required strings", function() {
|
||||||
// invalid string
|
// invalid string
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: ""
|
value: ""
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// valid string
|
// valid string
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test string"
|
value: "test string"
|
||||||
|
}
|
||||||
|
assertValidateParam(param, [])
|
||||||
|
|
||||||
|
// valid string with min and max length
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 50,
|
||||||
|
minLength: 1
|
||||||
|
}
|
||||||
|
assertValidateParam(param, [])
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
|
||||||
expect( result ).toEqual( [] )
|
it("validates required strings with min and max length", function() {
|
||||||
|
// invalid string with max length
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 5
|
||||||
|
}
|
||||||
|
assertValidateParam(param, ["Value must be less than MaxLength"])
|
||||||
|
|
||||||
|
// invalid string with max length 0
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 0
|
||||||
|
}
|
||||||
|
assertValidateParam(param, ["Value must be less than MaxLength"])
|
||||||
|
|
||||||
|
// invalid string with min length
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
minLength: 50
|
||||||
|
}
|
||||||
|
assertValidateParam(param, ["Value must be greater than MinLength"])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional strings", function() {
|
it("validates optional strings", function() {
|
||||||
// valid (empty) string
|
// valid (empty) string
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: ""
|
value: ""
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid string
|
// valid string
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test"
|
value: "test"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required files", function() {
|
it("validates required files", function() {
|
||||||
// invalid file
|
// invalid file
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "file",
|
type: "file",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// valid file
|
// valid file
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "file",
|
type: "file",
|
||||||
value: new win.File()
|
value: new win.File()
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional files", function() {
|
it("validates optional files", function() {
|
||||||
// invalid file
|
// invalid file
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file",
|
||||||
value: "not a file"
|
value: "not a file"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Value must be a file"])
|
||||||
expect( result ).toEqual( ["Value must be a file"] )
|
|
||||||
|
|
||||||
// valid (empty) file
|
// valid (empty) file
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid file
|
// valid file
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file",
|
||||||
value: new win.File()
|
value: new win.File()
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required arrays", function() {
|
it("validates required arrays", function() {
|
||||||
// invalid (empty) array
|
// invalid (empty) array
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: []
|
value: []
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// invalid (not an array)
|
// invalid (not an array)
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// invalid array, items do not match correct type
|
// invalid array, items do not match correct type
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: [1],
|
value: [1],
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [{index: 0, error: "Value must be a string"}])
|
||||||
expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )
|
|
||||||
|
|
||||||
// valid array, with no 'type' for items
|
// valid array, with no 'type' for items
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["1"]
|
value: ["1"]
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid array, items match type
|
// valid array, items match type
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["1"],
|
value: ["1"],
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional arrays", function() {
|
it("validates optional arrays", function() {
|
||||||
// valid, empty array
|
// valid, empty array
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: []
|
value: []
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// invalid, items do not match correct type
|
// invalid, items do not match correct type
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["number"],
|
value: ["number"],
|
||||||
items: {
|
items: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [{index: 0, error: "Value must be a number"}])
|
||||||
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
|
|
||||||
|
|
||||||
// valid
|
// valid
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["test"],
|
value: ["test"],
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required booleans", function() {
|
it("validates required booleans", function() {
|
||||||
// invalid boolean value
|
// invalid boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// invalid boolean value (not a boolean)
|
// invalid boolean value (not a boolean)
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: "test string"
|
value: "test string"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: "true"
|
value: "true"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false
|
value: false
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional booleans", function() {
|
it("validates optional booleans", function() {
|
||||||
// valid (empty) boolean value
|
// valid (empty) boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// invalid boolean value (not a boolean)
|
// invalid boolean value (not a boolean)
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: "test string"
|
value: "test string"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Value must be a boolean"])
|
||||||
expect( result ).toEqual( ["Value must be a boolean"] )
|
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: "true"
|
value: "true"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false
|
value: false
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required numbers", function() {
|
it("validates required numbers", function() {
|
||||||
// invalid number, string instead of a number
|
// invalid number, string instead of a number
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: "test"
|
value: "test"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// invalid number, undefined value
|
// invalid number, undefined value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// valid number
|
// valid number with min and max
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: 10
|
value: 10,
|
||||||
})
|
minimum: 5,
|
||||||
result = validateParam( param, false )
|
maximum: 99
|
||||||
expect( result ).toEqual( [] )
|
}
|
||||||
|
assertValidateParam(param, [])
|
||||||
|
|
||||||
|
// valid negative number with min and max
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: -10,
|
||||||
|
minimum: -50,
|
||||||
|
maximum: -5
|
||||||
|
}
|
||||||
|
assertValidateParam(param, [])
|
||||||
|
|
||||||
|
// invalid number with maximum:0
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: 1,
|
||||||
|
maximum: 0
|
||||||
|
}
|
||||||
|
assertValidateParam(param, ["Value must be less than Maximum"])
|
||||||
|
|
||||||
|
// invalid number with minimum:0
|
||||||
|
param = {
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: -10,
|
||||||
|
minimum: 0
|
||||||
|
}
|
||||||
|
assertValidateParam(param, ["Value must be greater than Minimum"])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional numbers", function() {
|
it("validates optional numbers", function() {
|
||||||
// invalid number, string instead of a number
|
// invalid number, string instead of a number
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: "test"
|
value: "test"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Value must be a number"])
|
||||||
expect( result ).toEqual( ["Value must be a number"] )
|
|
||||||
|
|
||||||
// valid (empty) number
|
// valid (empty) number
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// valid number
|
// valid number
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: 10
|
value: 10
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required integers", function() {
|
it("validates required integers", function() {
|
||||||
// invalid integer, string instead of an integer
|
// invalid integer, string instead of an integer
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: "test"
|
value: "test"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// invalid integer, undefined value
|
// invalid integer, undefined value
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Required field is not provided"])
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
|
||||||
|
|
||||||
// valid integer
|
// valid integer
|
||||||
param = fromJS({
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: 10
|
value: 10
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional integers", function() {
|
it("validates optional integers", function() {
|
||||||
// invalid integer, string instead of an integer
|
// invalid integer, string instead of an integer
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: "test"
|
value: "test"
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, ["Value must be an integer"])
|
||||||
expect( result ).toEqual( ["Value must be an integer"] )
|
|
||||||
|
|
||||||
// valid (empty) integer
|
// valid (empty) integer
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: undefined
|
value: undefined
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// integers
|
// integers
|
||||||
param = fromJS({
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer",
|
||||||
value: 10
|
value: 10
|
||||||
})
|
}
|
||||||
result = validateParam( param, false )
|
assertValidateParam(param, [])
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -583,7 +739,7 @@ describe("utils", function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe.only("getAcceptControllingResponse", () => {
|
describe("getAcceptControllingResponse", () => {
|
||||||
it("should return the first 2xx response with a media type", () => {
|
it("should return the first 2xx response with a media type", () => {
|
||||||
const responses = fromJSOrdered({
|
const responses = fromJSOrdered({
|
||||||
"200": {
|
"200": {
|
||||||
|
|||||||
33
test/xss/info-sanitization.js
Normal file
33
test/xss/info-sanitization.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { render } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import Info from "components/info"
|
||||||
|
import Markdown from "components/providers/markdown"
|
||||||
|
|
||||||
|
describe("<Info/> Sanitization", function(){
|
||||||
|
const dummyComponent = () => null
|
||||||
|
const components = {
|
||||||
|
Markdown
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
getComponent: c => components[c] || dummyComponent,
|
||||||
|
info: fromJS({
|
||||||
|
title: "Test Title **strong** <script>alert(1)</script>",
|
||||||
|
description: "Description *with* <script>Markdown</script>"
|
||||||
|
}),
|
||||||
|
host: "example.test",
|
||||||
|
basePath: "/api"
|
||||||
|
}
|
||||||
|
|
||||||
|
it("renders sanitized .title content", function(){
|
||||||
|
let wrapper = render(<Info {...props}/>)
|
||||||
|
expect(wrapper.find(".title").html()).toEqual("Test Title **strong** <script>alert(1)</script>")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders sanitized .description content", function() {
|
||||||
|
let wrapper = render(<Info {...props}/>)
|
||||||
|
expect(wrapper.find(".description").html()).toEqual("<div class=\"markdown\"><p>Description <em>with</em> </p>\n</div>")
|
||||||
|
})
|
||||||
|
})
|
||||||
36
test/xss/markdown-script-sanitization.js
Normal file
36
test/xss/markdown-script-sanitization.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { render } from "enzyme"
|
||||||
|
import Markdown from "components/providers/markdown"
|
||||||
|
import { Markdown as OAS3Markdown } from "corePlugins/oas3/wrap-components/markdown.js"
|
||||||
|
|
||||||
|
describe("Markdown Script Sanitization", function() {
|
||||||
|
describe("Swagger 2.0", function() {
|
||||||
|
it("sanitizes <script> elements", function() {
|
||||||
|
const str = `script <script>alert(1)</script>`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p>script </p>\n</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sanitizes <img> elements", function() {
|
||||||
|
const str = `<img src=x onerror="alert('img-in-description')">`
|
||||||
|
const el = render(<Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="markdown"><p><img src="x"></p>\n</div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("OAS 3", function() {
|
||||||
|
it("sanitizes <script> elements", function() {
|
||||||
|
const str = `script <script>alert(1)</script>`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p>script </p></div></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sanitizes <img> elements", function() {
|
||||||
|
const str = `<img src=x onerror="alert('img-in-description')">`
|
||||||
|
const el = render(<OAS3Markdown source={str} />)
|
||||||
|
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><img src="x"></div></div>`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -11,7 +11,7 @@ let rules = [
|
|||||||
name: "[name].js"
|
name: "[name].js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ loader: "babel-loader" }
|
{ loader: "babel-loader?retainLines=true" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let rules = [
|
|||||||
name: "[name].js"
|
name: "[name].js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ loader: "babel-loader" }
|
{ loader: "babel-loader?retainLines=true" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ let rules = [
|
|||||||
name: "[name].js"
|
name: "[name].js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ loader: "babel-loader" }
|
{ loader: "babel-loader?retainLines=true" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -9,13 +9,7 @@ const rules = [
|
|||||||
inline: true
|
inline: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ loader: "babel-loader" }
|
{ loader: "babel-loader?retainLines=true" }
|
||||||
]
|
|
||||||
},
|
|
||||||
{ test: /\.(jsx)(\?.*)?$/,
|
|
||||||
use: [
|
|
||||||
{ loader: "react-hot-loader" },
|
|
||||||
{ loader: "babel-loader" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ test: /\.(css)(\?.*)?$/,
|
{ test: /\.(css)(\?.*)?$/,
|
||||||
@@ -48,7 +42,7 @@ module.exports = require("./make-webpack-config")(rules, {
|
|||||||
_special: {
|
_special: {
|
||||||
separateStylesheets: false,
|
separateStylesheets: false,
|
||||||
},
|
},
|
||||||
devtool: "eval",
|
devtool: "eval-source-map",
|
||||||
entry: {
|
entry: {
|
||||||
"swagger-ui-bundle": [
|
"swagger-ui-bundle": [
|
||||||
"./src/polyfills",
|
"./src/polyfills",
|
||||||
|
|||||||
Reference in New Issue
Block a user