mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-06 21:30:21 +03:00
Merge addd10b762
into 5e5db72ea4
This commit is contained in:
commit
761bdca928
12
lib/components/AuthScopes/auth-scopes.html
Normal file
12
lib/components/AuthScopes/auth-scopes.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<ng-template [ngIf]="scopes">
|
||||||
|
<span class="hint--html hint--bottom-left hint--large oauth-scopes-hint">
|
||||||
|
!
|
||||||
|
<div class="oauth-scopes hint__content">
|
||||||
|
<span class="oauth-scopes-header">OAuth2 Scopes</span>
|
||||||
|
<div *ngFor="let scope of scopes.scopes" class="oauth-scope">
|
||||||
|
<p class="oauth-scope-name"> {{scope.name}} </p>
|
||||||
|
<p class="oauth-scope-description"> {{scope.description}} </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
32
lib/components/AuthScopes/auth-scopes.scss
Normal file
32
lib/components/AuthScopes/auth-scopes.scss
Normal file
|
@ -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;
|
||||||
|
}
|
32
lib/components/AuthScopes/auth-scopes.ts
Normal file
32
lib/components/AuthScopes/auth-scopes.ts
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="operation-content">
|
<div class="operation-content">
|
||||||
<h2 class="operation-header sharable-header" [class.deprecated]="operation.deprecated">
|
<h2 class="operation-header sharable-header" [class.deprecated]="operation.deprecated">
|
||||||
<a class="share-link" href="#{{operation.anchor}}"></a>{{operation.summary}}
|
<a class="share-link" href="#{{operation.anchor}}"></a>{{operation.summary}}
|
||||||
|
<auth-scopes pointer="{{pointer}}/security"> </auth-scopes>
|
||||||
</h2>
|
</h2>
|
||||||
<endpoint-link *ngIf="pathInMiddlePanel"
|
<endpoint-link *ngIf="pathInMiddlePanel"
|
||||||
[verb]="operation.verb" [path]="operation.path"> </endpoint-link>
|
[verb]="operation.verb" [path]="operation.path"> </endpoint-link>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { ParamsList } from './ParamsList/params-list';
|
||||||
import { RequestSamples } from './RequestSamples/request-samples';
|
import { RequestSamples } from './RequestSamples/request-samples';
|
||||||
import { ResponsesList } from './ResponsesList/responses-list';
|
import { ResponsesList } from './ResponsesList/responses-list';
|
||||||
import { ResponsesSamples } from './ResponsesSamples/responses-samples';
|
import { ResponsesSamples } from './ResponsesSamples/responses-samples';
|
||||||
|
import { AuthScopes} from './AuthScopes/auth-scopes';
|
||||||
import { SchemaSample } from './SchemaSample/schema-sample';
|
import { SchemaSample } from './SchemaSample/schema-sample';
|
||||||
import { SideMenu, SideMenuItems } from './SideMenu/side-menu';
|
import { SideMenu, SideMenuItems } from './SideMenu/side-menu';
|
||||||
import { OperationsList } from './OperationsList/operations-list';
|
import { OperationsList } from './OperationsList/operations-list';
|
||||||
|
@ -23,10 +24,10 @@ import { Redoc } from './Redoc/redoc';
|
||||||
|
|
||||||
export const REDOC_DIRECTIVES = [
|
export const REDOC_DIRECTIVES = [
|
||||||
ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
|
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
|
LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink
|
||||||
];
|
];
|
||||||
|
|
||||||
export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
|
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 };
|
LoadingBar, SideMenuItems, ExternalDocs, EndpointLink };
|
||||||
|
|
|
@ -138,6 +138,42 @@ export class SpecManager {
|
||||||
return obj;
|
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[] {
|
getOperationParams(operationPtr:string):SwaggerParameter[] {
|
||||||
/* inject JsonPointer into array elements */
|
/* inject JsonPointer into array elements */
|
||||||
function injectPointers(array:SwaggerParameter[], root) {
|
function injectPointers(array:SwaggerParameter[], root) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import 'prismjs/components/prism-markup.js'; // xml
|
||||||
|
|
||||||
import 'dropkickjs/build/css/dropkick.css';
|
import 'dropkickjs/build/css/dropkick.css';
|
||||||
import 'prismjs/themes/prism-dark.css';
|
import 'prismjs/themes/prism-dark.css';
|
||||||
import 'hint.css/hint.base.css';
|
import 'html-hint/dist/html-hint.css';
|
||||||
|
|
||||||
if (!IS_PRODUCTION) {
|
if (!IS_PRODUCTION) {
|
||||||
require('@angular/platform-browser');
|
require('@angular/platform-browser');
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"css-loader": "^0.28.1",
|
"css-loader": "^0.28.1",
|
||||||
"deploy-to-gh-pages": "^1.3.3",
|
"deploy-to-gh-pages": "^1.3.3",
|
||||||
"dropkickjs": "^2.1.10",
|
"dropkickjs": "^2.1.10",
|
||||||
"hint.css": "^2.5.0",
|
"html-hint": "^0.2.4",
|
||||||
"http-server": "^0.10.0",
|
"http-server": "^0.10.0",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"istanbul-instrumenter-loader": "^2.0.0",
|
"istanbul-instrumenter-loader": "^2.0.0",
|
||||||
|
|
108
tests/schemas/schema-mgr-operation-security.json
Normal file
108
tests/schemas/schema-mgr-operation-security.json
Normal file
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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', () => {
|
describe('getOperationParams method', () => {
|
||||||
beforeEach((done:any) => {
|
beforeEach((done:any) => {
|
||||||
specMgr.load('/tests/schemas/schema-mgr-operationParams.json').then(done, done.fail);
|
specMgr.load('/tests/schemas/schema-mgr-operationParams.json').then(done, done.fail);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user