From 3b157dab6b1336ba4cac4a4afbaef771b03746e6 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 22 Jun 2017 20:12:01 -0500 Subject: [PATCH 1/5] Addresses issue #283 by adding oauth2 security scopes to operation docs --- lib/components/AuthScopes/auth-scopes.html | 12 ++ lib/components/AuthScopes/auth-scopes.scss | 32 ++++++ lib/components/AuthScopes/auth-scopes.ts | 32 ++++++ lib/components/Operation/operation.html | 1 + lib/components/index.ts | 5 +- lib/utils/spec-manager.ts | 36 ++++++ lib/vendor.ts | 2 +- package.json | 2 +- .../schema-mgr-operation-security.json | 108 ++++++++++++++++++ tests/unit/SpecManager.spec.ts | 27 +++++ 10 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 lib/components/AuthScopes/auth-scopes.html create mode 100644 lib/components/AuthScopes/auth-scopes.scss create mode 100644 lib/components/AuthScopes/auth-scopes.ts create mode 100644 tests/schemas/schema-mgr-operation-security.json diff --git a/lib/components/AuthScopes/auth-scopes.html b/lib/components/AuthScopes/auth-scopes.html new file mode 100644 index 00000000..e1a4e3a8 --- /dev/null +++ b/lib/components/AuthScopes/auth-scopes.html @@ -0,0 +1,12 @@ + + + ! +
+ OAuth2 Scopes +
+

{{scope.name}}

+

{{scope.description}}

+
+
+
+
diff --git a/lib/components/AuthScopes/auth-scopes.scss b/lib/components/AuthScopes/auth-scopes.scss new file mode 100644 index 00000000..9d1b4211 --- /dev/null +++ b/lib/components/AuthScopes/auth-scopes.scss @@ -0,0 +1,32 @@ +$hint-color: #e53935; + +.oauth-scopes-header { + font-weight: bold; +} + +.oauth-scope { + padding-top: 1.2em; +} + +.oauth-scope-description { + font-style: italic; + line-height: 0.2em; +} + +.oauth-scopes { + text-align: left; + white-space: nowrap; +} + +.oauth-scopes-hint { + width: 1.2em; + text-align: center; + border-radius: 50%; + vertical-align: middle; + color: $hint-color; + line-height: 1.2; + text-transform: none; + cursor: help; + border: 1px solid $hint-color; + float: right; +} diff --git a/lib/components/AuthScopes/auth-scopes.ts b/lib/components/AuthScopes/auth-scopes.ts new file mode 100644 index 00000000..0573b3c3 --- /dev/null +++ b/lib/components/AuthScopes/auth-scopes.ts @@ -0,0 +1,32 @@ +'use strict'; +import { Component, Input, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { BaseComponent, SpecManager } from '../base'; +import { SchemaHelper } from '../../services/schema-helper.service'; +import { ComponentParser } from '../../services/component-parser.service'; + +@Component({ + selector: 'auth-scopes', + templateUrl: './auth-scopes.html', + styleUrls: ['./auth-scopes.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AuthScopes extends BaseComponent implements OnInit { + @Input() pointer:string; + + public scopes: any; + + constructor(specMgr:SpecManager) { + super(specMgr); + } + + init() { + let theScopes = this.specMgr.getOperationScopes(this.pointer); + if (theScopes.length) { + this.scopes = {scopes: theScopes} + } + } + + ngOnInit() { + this.preinit(); + } +} diff --git a/lib/components/Operation/operation.html b/lib/components/Operation/operation.html index 4fa9a345..05d9f794 100644 --- a/lib/components/Operation/operation.html +++ b/lib/components/Operation/operation.html @@ -2,6 +2,7 @@

{{operation.summary}} +

diff --git a/lib/components/index.ts b/lib/components/index.ts index 719d20d6..fe5a48e5 100644 --- a/lib/components/index.ts +++ b/lib/components/index.ts @@ -8,6 +8,7 @@ import { ParamsList } from './ParamsList/params-list'; import { RequestSamples } from './RequestSamples/request-samples'; import { ResponsesList } from './ResponsesList/responses-list'; import { ResponsesSamples } from './ResponsesSamples/responses-samples'; +import { AuthScopes} from './AuthScopes/auth-scopes'; import { SchemaSample } from './SchemaSample/schema-sample'; import { SideMenu, SideMenuItems } from './SideMenu/side-menu'; import { OperationsList } from './OperationsList/operations-list'; @@ -23,10 +24,10 @@ import { Redoc } from './Redoc/redoc'; export const REDOC_DIRECTIVES = [ ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList, - ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions, + ResponsesSamples, AuthScopes, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions, LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink ]; export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList, -ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions, +ResponsesSamples, AuthScopes, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions, LoadingBar, SideMenuItems, ExternalDocs, EndpointLink }; diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index 084cf22b..66ae183b 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -137,6 +137,42 @@ export class SpecManager { return obj; } + getOperationScopes(operationPtr:string) { + let that = this; + function getSecurityDefinition(name:string, scope:string) { + let secDefs = that._schema.securityDefinitions; + if (secDefs[name] && secDefs[name].type === "oauth2") { + let availScopes = secDefs[name].scopes + if (availScopes && availScopes[scope]) { + return availScopes[scope]; + } + } + return null; + } + + let securityParams = this.byPointer(operationPtr) || []; + let scopes = []; + + // only support one security item per operation for now + let base = securityParams[0]; + + if (base && base[Object.keys(base)[0]]) { + let scopeObj = base[Object.keys(base)[0]]; + let authName = Object.keys(base)[0]; + Object.keys(scopeObj).forEach(key => { + let val = scopeObj[key]; + let desc = getSecurityDefinition(authName, val); + + // don't add if the security obj doesn't exist in the security definitions + if (desc) { + scopes.push({name: val, description: desc}); + } + }); + } + + return scopes; + } + getOperationParams(operationPtr:string):SwaggerParameter[] { /* inject JsonPointer into array elements */ function injectPointers(array:SwaggerParameter[], root) { diff --git a/lib/vendor.ts b/lib/vendor.ts index edbd8669..ebdc2515 100644 --- a/lib/vendor.ts +++ b/lib/vendor.ts @@ -22,7 +22,7 @@ import 'prismjs/components/prism-markup.js'; // xml import 'dropkickjs/build/css/dropkick.css'; import 'prismjs/themes/prism-dark.css'; -import 'hint.css/hint.base.css'; +import 'html-hint/dist/html-hint.css'; if (!IS_PRODUCTION) { require('@angular/platform-browser'); diff --git a/package.json b/package.json index 91ef8ee2..a4a1e5fb 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "css-loader": "^0.28.1", "deploy-to-gh-pages": "^1.3.3", "dropkickjs": "^2.1.10", - "hint.css": "^2.5.0", + "html-hint": "^0.2.4", "http-server": "^0.10.0", "https-browserify": "^1.0.0", "istanbul-instrumenter-loader": "^2.0.0", diff --git a/tests/schemas/schema-mgr-operation-security.json b/tests/schemas/schema-mgr-operation-security.json new file mode 100644 index 00000000..ed9e613b --- /dev/null +++ b/tests/schemas/schema-mgr-operation-security.json @@ -0,0 +1,108 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Test schema" + }, + "host": "petstore.swagger.io", + "basePath": "/v2/", + "parameters": { + "extparam": { + "name": "extParam", + "in": "query", + "type": "integer" + } + }, + "securityDefinitions": { + "petstore_auth": { + "type": "oauth2", + "authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog", + "flow": "implicit", + "scopes": { + "write:pets": "modify pets in your account", + "read:pets": "read your pets" + } + }, + "github_auth": { + "type": "oauth2", + "authorizationUrl": "https://api.github.com/authorize", + "flow": "implicit", + "scopes": { + "write:account": "modify your account", + "read:account": "read your account" + } + }, + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + } + }, + "paths": { + "test1": { + "parameters": [ + { + "name": "pathParam", + "in": "path", + "type": "string" + } + ], + "get": { + "summary": "test get", + "parameters": [ + { + "name": "operationParam", + "in": "path", + "type": "string" + } + ], + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "test2": { + "parameters": [ + { "$ref": "#/parameters/extparam" } + ], + "get": { + "summary": "test get", + "parameters": [ + { + "name": "operationParam", + "in": "path", + "type": "string" + } + ] + } + }, + "test3": { + "get": { + "summary": "test get", + "parameters": [ + { "$ref": "#/parameters/extparam" } + ], + "security": [ + { + "github_auth": [ + "write:account" + ] + } + ] + } + }, + "test4": { + "parameters": { + "$ref": "#/parameters/extparam" + }, + "get": { + "summary": "test get" + } + } + } +} diff --git a/tests/unit/SpecManager.spec.ts b/tests/unit/SpecManager.spec.ts index 5872c32e..c8841cb7 100644 --- a/tests/unit/SpecManager.spec.ts +++ b/tests/unit/SpecManager.spec.ts @@ -105,6 +105,33 @@ describe('Utils', () => { }); }); + describe('getOperationScopes method', () => { + beforeEach(function (done) { + specMgr.load('/tests/schemas/schema-mgr-operation-security.json').then(done, done.fail); + }); + + it('should handle operation oauth2 scopes', () => { + let scopes = specMgr.getOperationScopes('/paths/test1/get/security'); + scopes.length.should.be.equal(2); + scopes[0].name.should.be.equal('write:pets'); + scopes[0].description.should.be.equal('modify pets in your account'); + scopes[1].name.should.be.equal('read:pets'); + scopes[1].description.should.be.equal('read your pets'); + }); + + it('should handle operation scopes when multiple definitions are used', () => { + let scopes = specMgr.getOperationScopes('/paths/test3/get/security'); + scopes.length.should.be.equal(1); + scopes[0].name.should.be.equal('write:account'); + scopes[0].description.should.be.equal('modify your account');\ + }); + + it('should handle the case when no security is present', () => { + let scopes = specMgr.getOperationScopes('/paths/test2/get/security'); + scopes.length.should.be.equal(0); + }); + }); + describe('getOperationParams method', () => { beforeEach((done:any) => { specMgr.load('/tests/schemas/schema-mgr-operationParams.json').then(done, done.fail); From addd10b762dafc0f2fe9a81e0df5fe8362c4e209 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 22 Jun 2017 20:45:19 -0500 Subject: [PATCH 2/5] fix lint errors --- lib/utils/spec-manager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index 66ae183b..14f08e11 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -141,8 +141,8 @@ export class SpecManager { let that = this; function getSecurityDefinition(name:string, scope:string) { let secDefs = that._schema.securityDefinitions; - if (secDefs[name] && secDefs[name].type === "oauth2") { - let availScopes = secDefs[name].scopes + if (secDefs[name] && secDefs[name].type === 'oauth2') { + let availScopes = secDefs[name].scopes; if (availScopes && availScopes[scope]) { return availScopes[scope]; } @@ -162,7 +162,7 @@ export class SpecManager { Object.keys(scopeObj).forEach(key => { let val = scopeObj[key]; let desc = getSecurityDefinition(authName, val); - + // don't add if the security obj doesn't exist in the security definitions if (desc) { scopes.push({name: val, description: desc}); From ab069bd91c328db30445f58479f8d80d8bd85757 Mon Sep 17 00:00:00 2001 From: abc Date: Tue, 18 Jul 2017 16:09:06 +0100 Subject: [PATCH 3/5] Fixes for the scopes --- demo/swagger.yaml | 3 +- lib/components/AuthScopes/auth-scopes.html | 13 +++++---- lib/components/AuthScopes/auth-scopes.scss | 32 ---------------------- lib/components/AuthScopes/auth-scopes.ts | 1 - lib/utils/spec-manager.ts | 5 ++-- lib/vendor.ts | 2 +- package.json | 2 +- 7 files changed, 13 insertions(+), 45 deletions(-) delete mode 100644 lib/components/AuthScopes/auth-scopes.scss diff --git a/demo/swagger.yaml b/demo/swagger.yaml index 63a0bcbb..ed06f5db 100644 --- a/demo/swagger.yaml +++ b/demo/swagger.yaml @@ -336,6 +336,7 @@ paths: summary: Finds Pets by tags description: 'Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.' operationId: findPetsByTags + deprecated: true produces: - application/xml - application/json @@ -858,4 +859,4 @@ definitions: type: integer format: int32 xml: - name: User + name: User \ No newline at end of file diff --git a/lib/components/AuthScopes/auth-scopes.html b/lib/components/AuthScopes/auth-scopes.html index e1a4e3a8..3d4adb82 100644 --- a/lib/components/AuthScopes/auth-scopes.html +++ b/lib/components/AuthScopes/auth-scopes.html @@ -1,12 +1,13 @@ - - !
OAuth2 Scopes -
-

{{scope.name}}

-

{{scope.description}}

+
+ + + + +
- diff --git a/lib/components/AuthScopes/auth-scopes.scss b/lib/components/AuthScopes/auth-scopes.scss deleted file mode 100644 index 9d1b4211..00000000 --- a/lib/components/AuthScopes/auth-scopes.scss +++ /dev/null @@ -1,32 +0,0 @@ -$hint-color: #e53935; - -.oauth-scopes-header { - font-weight: bold; -} - -.oauth-scope { - padding-top: 1.2em; -} - -.oauth-scope-description { - font-style: italic; - line-height: 0.2em; -} - -.oauth-scopes { - text-align: left; - white-space: nowrap; -} - -.oauth-scopes-hint { - width: 1.2em; - text-align: center; - border-radius: 50%; - vertical-align: middle; - color: $hint-color; - line-height: 1.2; - text-transform: none; - cursor: help; - border: 1px solid $hint-color; - float: right; -} diff --git a/lib/components/AuthScopes/auth-scopes.ts b/lib/components/AuthScopes/auth-scopes.ts index 0573b3c3..b73d4a39 100644 --- a/lib/components/AuthScopes/auth-scopes.ts +++ b/lib/components/AuthScopes/auth-scopes.ts @@ -7,7 +7,6 @@ import { ComponentParser } from '../../services/component-parser.service'; @Component({ selector: 'auth-scopes', templateUrl: './auth-scopes.html', - styleUrls: ['./auth-scopes.css'], changeDetection: ChangeDetectionStrategy.OnPush }) export class AuthScopes extends BaseComponent implements OnInit { diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index 14f08e11..6a04f5e6 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -138,9 +138,8 @@ export class SpecManager { } getOperationScopes(operationPtr:string) { - let that = this; - function getSecurityDefinition(name:string, scope:string) { - let secDefs = that._schema.securityDefinitions; + const getSecurityDefinition = (name: string, scope: string) => { + let secDefs = this._schema.securityDefinitions; if (secDefs[name] && secDefs[name].type === 'oauth2') { let availScopes = secDefs[name].scopes; if (availScopes && availScopes[scope]) { diff --git a/lib/vendor.ts b/lib/vendor.ts index ebdc2515..edbd8669 100644 --- a/lib/vendor.ts +++ b/lib/vendor.ts @@ -22,7 +22,7 @@ import 'prismjs/components/prism-markup.js'; // xml import 'dropkickjs/build/css/dropkick.css'; import 'prismjs/themes/prism-dark.css'; -import 'html-hint/dist/html-hint.css'; +import 'hint.css/hint.base.css'; if (!IS_PRODUCTION) { require('@angular/platform-browser'); diff --git a/package.json b/package.json index a4a1e5fb..91ef8ee2 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "css-loader": "^0.28.1", "deploy-to-gh-pages": "^1.3.3", "dropkickjs": "^2.1.10", - "html-hint": "^0.2.4", + "hint.css": "^2.5.0", "http-server": "^0.10.0", "https-browserify": "^1.0.0", "istanbul-instrumenter-loader": "^2.0.0", From 5ce1352f5342887e0becc0580430ff59ff446dd7 Mon Sep 17 00:00:00 2001 From: George Wilson Date: Tue, 25 Jul 2017 11:18:03 +0100 Subject: [PATCH 4/5] Add semi-colon --- lib/utils/spec-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index 6a04f5e6..4723c31b 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -147,7 +147,7 @@ export class SpecManager { } } return null; - } + }; let securityParams = this.byPointer(operationPtr) || []; let scopes = []; From d5a5615b3a613850f011308c0560423872a2bee0 Mon Sep 17 00:00:00 2001 From: George Wilson Date: Fri, 28 Jul 2017 00:00:46 +0100 Subject: [PATCH 5/5] Remove accidentally commited thing --- demo/swagger.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/swagger.yaml b/demo/swagger.yaml index ed06f5db..63a0bcbb 100644 --- a/demo/swagger.yaml +++ b/demo/swagger.yaml @@ -336,7 +336,6 @@ paths: summary: Finds Pets by tags description: 'Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.' operationId: findPetsByTags - deprecated: true produces: - application/xml - application/json @@ -859,4 +858,4 @@ definitions: type: integer format: int32 xml: - name: User \ No newline at end of file + name: User