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 @@
+
+
+ !
+
+
+
+
{{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 3ddea4f5..9eba10ae 100644
--- a/lib/components/Operation/operation.html
+++ b/lib/components/Operation/operation.html
@@ -2,6 +2,7 @@
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 3c3ce3ee..029ee6b3 100644
--- a/lib/utils/spec-manager.ts
+++ b/lib/utils/spec-manager.ts
@@ -138,6 +138,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 5b5d6362..603cefa9 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);