Bug/auth operation btn errorbubble
@@ -2,6 +2,7 @@ node_modules | |||
.idea | |||
.deps_check | |||
.DS_Store | |||
.nyc_output | |||
npm-debug.log* | |||
.eslintcache | |||
package-lock.json | |||
@@ -33,6 +33,7 @@ | |||
"test-in-node": "npm run lint-errors && npm run just-test-in-node", | |||
"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-check-coverage": "nyc npm run just-test-in-node", | |||
"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", | |||
"mock-api": "json-server --watch test/e2e/db.json --port 3204", | |||
@@ -127,6 +128,7 @@ | |||
"node-sass": "^4.5.0", | |||
"npm-run-all": "4.0.2", | |||
"null-loader": "0.1.1", | |||
"nyc": "^11.3.0", | |||
"open": "0.0.5", | |||
"postcss-loader": "2.0.6", | |||
"raw-loader": "0.5.1", | |||
@@ -152,5 +154,11 @@ | |||
], | |||
"optionalDependencies": { | |||
"webpack-dev-server": "2.5.0" | |||
}, | |||
"nyc": { | |||
"all": true, | |||
"include": [ | |||
"**/src/core/plugins/**.js" | |||
] | |||
} | |||
} |
@@ -1,25 +1,23 @@ | |||
import React from "react" | |||
import PropTypes from "prop-types" | |||
import ImPropTypes from "react-immutable-proptypes" | |||
export default class AuthorizeOperationBtn extends React.Component { | |||
static propTypes = { | |||
isAuthorized: PropTypes.bool.isRequired, | |||
onClick: PropTypes.func | |||
} | |||
onClick =(e) => { | |||
e.stopPropagation() | |||
let { onClick } = this.props | |||
let { security, authActions, authSelectors } = this.props | |||
let definitions = authSelectors.getDefinitionsByNames(security) | |||
authActions.showDefinitions(definitions) | |||
if(onClick) { | |||
onClick() | |||
} | |||
} | |||
render() { | |||
let { security, authSelectors } = this.props | |||
let isAuthorized = authSelectors.isAuthorized(security) | |||
if(isAuthorized === null) { | |||
return null | |||
} | |||
let { isAuthorized } = this.props | |||
return ( | |||
<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 | |||
} | |||
} |
@@ -183,9 +183,13 @@ export default class Operation extends PureComponent { | |||
{ | |||
(!security || !security.count()) ? null : | |||
<AuthorizeOperationBtn authActions={ authActions } | |||
security={ security } | |||
authSelectors={ authSelectors }/> | |||
<AuthorizeOperationBtn | |||
isAuthorized={ authSelectors.isAuthorized(security) } | |||
onClick={() => { | |||
const applicableDefinitions = authSelectors.definitionsForRequirements(security) | |||
authActions.showDefinitions(applicableDefinitions) | |||
}} | |||
/> | |||
} | |||
</div> | |||
@@ -11,7 +11,7 @@ export const shownDefinitions = createSelector( | |||
export const definitionsToAuthorize = createSelector( | |||
state, | |||
() => ( { specSelectors } ) => { | |||
let definitions = specSelectors.securityDefinitions() | |||
let definitions = specSelectors.securityDefinitions() || Map({}) | |||
let list = List() | |||
//todo refactor | |||
@@ -28,6 +28,7 @@ export const definitionsToAuthorize = createSelector( | |||
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 result = List() | |||
@@ -58,6 +59,13 @@ export const getDefinitionsByNames = ( state, securities ) => ( { specSelectors | |||
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( | |||
state, | |||
auth => auth.get("authorized") || Map() | |||
@@ -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([]) | |||
}) | |||
}) | |||
}) |