Merge branch 'master' into ft/3052-extensions
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ node_modules
|
|||||||
.idea
|
.idea
|
||||||
.deps_check
|
.deps_check
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.nyc_output
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
.eslintcache
|
.eslintcache
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"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 test/xss",
|
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package test/xss",
|
||||||
|
"just-check-coverage": "nyc npm run just-test-in-node",
|
||||||
"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",
|
||||||
@@ -127,6 +128,7 @@
|
|||||||
"node-sass": "^4.5.0",
|
"node-sass": "^4.5.0",
|
||||||
"npm-run-all": "4.0.2",
|
"npm-run-all": "4.0.2",
|
||||||
"null-loader": "0.1.1",
|
"null-loader": "0.1.1",
|
||||||
|
"nyc": "^11.3.0",
|
||||||
"open": "0.0.5",
|
"open": "0.0.5",
|
||||||
"postcss-loader": "2.0.6",
|
"postcss-loader": "2.0.6",
|
||||||
"raw-loader": "0.5.1",
|
"raw-loader": "0.5.1",
|
||||||
@@ -152,5 +154,11 @@
|
|||||||
],
|
],
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"webpack-dev-server": "2.5.0"
|
"webpack-dev-server": "2.5.0"
|
||||||
|
},
|
||||||
|
"nyc": {
|
||||||
|
"all": true,
|
||||||
|
"include": [
|
||||||
|
"**/src/core/plugins/**.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import ImPropTypes from "react-immutable-proptypes"
|
|
||||||
|
|
||||||
export default class AuthorizeOperationBtn extends React.Component {
|
export default class AuthorizeOperationBtn extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
isAuthorized: PropTypes.bool.isRequired,
|
||||||
|
onClick: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
onClick =(e) => {
|
onClick =(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
let { onClick } = this.props
|
||||||
|
|
||||||
let { security, authActions, authSelectors } = this.props
|
if(onClick) {
|
||||||
let definitions = authSelectors.getDefinitionsByNames(security)
|
onClick()
|
||||||
|
}
|
||||||
authActions.showDefinitions(definitions)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { security, authSelectors } = this.props
|
let { isAuthorized } = this.props
|
||||||
|
|
||||||
let isAuthorized = authSelectors.isAuthorized(security)
|
|
||||||
|
|
||||||
if(isAuthorized === null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
|
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
|
||||||
@@ -30,10 +28,4 @@ export default class AuthorizeOperationBtn extends React.Component {
|
|||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
authSelectors: PropTypes.object.isRequired,
|
|
||||||
authActions: PropTypes.object.isRequired,
|
|
||||||
security: ImPropTypes.iterable.isRequired
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from "react"
|
import React, { PureComponent } from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
export default class Model extends Component {
|
export default class Model extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
schema: PropTypes.object.isRequired,
|
schema: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -185,9 +185,13 @@ export default class Operation extends PureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
(!security || !security.count()) ? null :
|
(!security || !security.count()) ? null :
|
||||||
<AuthorizeOperationBtn authActions={ authActions }
|
<AuthorizeOperationBtn
|
||||||
security={ security }
|
isAuthorized={ authSelectors.isAuthorized(security) }
|
||||||
authSelectors={ authSelectors }/>
|
onClick={() => {
|
||||||
|
const applicableDefinitions = authSelectors.definitionsForRequirements(security)
|
||||||
|
authActions.showDefinitions(applicableDefinitions)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,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() || Map({})
|
||||||
let list = List()
|
let list = List()
|
||||||
|
|
||||||
//todo refactor
|
//todo refactor
|
||||||
@@ -28,6 +28,7 @@ export const definitionsToAuthorize = createSelector(
|
|||||||
|
|
||||||
|
|
||||||
export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors } ) => {
|
export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors } ) => {
|
||||||
|
console.warn("WARNING: getDefinitionsByNames is deprecated and will be removed in the next major version.")
|
||||||
let securityDefinitions = specSelectors.securityDefinitions()
|
let securityDefinitions = specSelectors.securityDefinitions()
|
||||||
let result = List()
|
let result = List()
|
||||||
|
|
||||||
@@ -58,6 +59,13 @@ export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const definitionsForRequirements = (state, securities = List()) => ({ authSelectors }) => {
|
||||||
|
const allDefinitions = authSelectors.definitionsToAuthorize() || List()
|
||||||
|
return allDefinitions.filter((def) => {
|
||||||
|
return securities.some(sec => sec.get(def.keySeq().first()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const authorized = createSelector(
|
export const authorized = createSelector(
|
||||||
state,
|
state,
|
||||||
auth => auth.get("authorized") || Map()
|
auth => auth.get("authorized") || Map()
|
||||||
|
|||||||
133
test/core/plugins/auth/selectors.js
Normal file
133
test/core/plugins/auth/selectors.js
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import expect from "expect"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import { definitionsToAuthorize, definitionsForRequirements } from "corePlugins/auth/selectors"
|
||||||
|
|
||||||
|
describe("auth plugin - selectors", () => {
|
||||||
|
describe("definitionsToAuthorize", () => {
|
||||||
|
it("should return securityDefinitions as a List", () => {
|
||||||
|
const securityDefinitions = {
|
||||||
|
"petstore_auth": {
|
||||||
|
"type": "oauth2",
|
||||||
|
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
|
||||||
|
"flow": "implicit",
|
||||||
|
"scopes": {
|
||||||
|
"write:pets": "modify pets in your account",
|
||||||
|
"read:pets": "read your pets"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "api_key",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const system = {
|
||||||
|
specSelectors: {
|
||||||
|
securityDefinitions() {
|
||||||
|
return fromJS(securityDefinitions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = definitionsToAuthorize({})(system)
|
||||||
|
|
||||||
|
expect(res.toJS()).toEqual([
|
||||||
|
{
|
||||||
|
"petstore_auth": securityDefinitions["petstore_auth"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": securityDefinitions["api_key"]
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should fail gracefully with bad data", () => {
|
||||||
|
const securityDefinitions = null
|
||||||
|
|
||||||
|
const system = {
|
||||||
|
specSelectors: {
|
||||||
|
securityDefinitions() {
|
||||||
|
return fromJS(securityDefinitions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = definitionsToAuthorize({})(system)
|
||||||
|
|
||||||
|
expect(res.toJS()).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("definitionsForRequirements", () => {
|
||||||
|
it("should return applicable securityDefinitions as a List", () => {
|
||||||
|
const securityDefinitions = {
|
||||||
|
"petstore_auth": {
|
||||||
|
"type": "oauth2",
|
||||||
|
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
|
||||||
|
"flow": "implicit",
|
||||||
|
"scopes": {
|
||||||
|
"write:pets": "modify pets in your account",
|
||||||
|
"read:pets": "read your pets"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "api_key",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const system = {
|
||||||
|
authSelectors: {
|
||||||
|
definitionsToAuthorize() {
|
||||||
|
return fromJS([
|
||||||
|
{
|
||||||
|
"petstore_auth": securityDefinitions["petstore_auth"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": securityDefinitions["api_key"]
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const securities = fromJS([
|
||||||
|
{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const res = definitionsForRequirements({}, securities)(system)
|
||||||
|
|
||||||
|
expect(res.toJS()).toEqual([
|
||||||
|
{
|
||||||
|
"petstore_auth": securityDefinitions["petstore_auth"]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should fail gracefully with bad data", () => {
|
||||||
|
const securityDefinitions = null
|
||||||
|
|
||||||
|
const system = {
|
||||||
|
authSelectors: {
|
||||||
|
definitionsToAuthorize() {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const securities = null
|
||||||
|
|
||||||
|
const res = definitionsForRequirements({}, securities)(system)
|
||||||
|
|
||||||
|
expect(res.toJS()).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user