diff --git a/docs/redoc-vendor-extensions.md b/docs/redoc-vendor-extensions.md index 4f012fd2..2265b077 100644 --- a/docs/redoc-vendor-extensions.md +++ b/docs/redoc-vendor-extensions.md @@ -157,6 +157,51 @@ description: Pagination description (can use markdown syntax) x-traitTag: true ``` +### Permission Object vendor extensions + +#### x-permissions + +| Field Name | Type | Description | +| :------------- | :------: | :---------- | +| x-permissions | Object | Define the several permissions available for the API and associated to the operations | + +###### Usage in ReDoc +`x-permissions` are rendered bellow the API description of ReDoc + +###### x-permissions example (main declaration) + +yaml +```yaml +swagger: '2.0' +info: + ... +tags: [...] +x-permissions: + admin: + title: Pet store admin + description: 'Pet store Admin have special privileges on PetStore API allowing them to manage their store and users from their company ' + user: + title: Pet Store user + description: 'Pet store user' +``` + +##### Usage in Redoc operations +`x-permissions` are rendered above the Operation description of ReDoc +###### x-permissions example (operation declaration) + +yaml +```yaml +/user/logout: + get: + tags: + - "user" + x-permissions: + - name: "admin" + - name: "user" +``` + + + ### Operation Object vendor extensions Extends OpenAPI [Operation Object](http://swagger.io/specification/#operationObject) #### x-code-samples diff --git a/lib/components/Operation/operation.html b/lib/components/Operation/operation.html index 3ddea4f5..57bc24f2 100644 --- a/lib/components/Operation/operation.html +++ b/lib/components/Operation/operation.html @@ -8,6 +8,10 @@
+diff --git a/lib/components/Operation/operation.scss b/lib/components/Operation/operation.scss index 708b71c8..8fabebfe 100644 --- a/lib/components/Operation/operation.scss +++ b/lib/components/Operation/operation.scss @@ -53,6 +53,30 @@ } } +.operation-permissions { + margin-top: 20px; + + font-size: 14px; + padding: 0.2em 0; + margin: 3em 0 1.1em; + color: #253137; + font-weight: normal; + + a { + font-size: 12px; + font-family: Courier, monospace; + background-color: rgba(38, 50, 56, 0.02); + border: 1px solid rgba(38, 50, 56, 0.1); + margin: 2px 3px; + padding: 0px 5px; + border-radius: 2px; + color: #263238; + display: inline-block; + min-width: 20px; + text-align: center; + } +} + .operation-content, .operation-samples { display: block; box-sizing: border-box; diff --git a/lib/components/Operation/operation.spec.ts b/lib/components/Operation/operation.spec.ts index 44be2aae..40ba98c5 100644 --- a/lib/components/Operation/operation.spec.ts +++ b/lib/components/Operation/operation.spec.ts @@ -10,8 +10,8 @@ import { import { getChildDebugElement } from '../../../tests/helpers'; import { Operation } from './operation'; -import { SpecManager } from '../../utils/spec-manager';; -import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';; +import { SpecManager } from '../../utils/spec-manager'; +import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for'; describe('Redoc components', () => { beforeEach(() => { diff --git a/lib/components/Operation/operation.ts b/lib/components/Operation/operation.ts index dc86e7e6..92ee79f1 100644 --- a/lib/components/Operation/operation.ts +++ b/lib/components/Operation/operation.ts @@ -12,6 +12,7 @@ export interface OperationInfo { path: string; info: { tags: string[]; + permissions: string[]; description: string; }; bodyParam: any; @@ -20,7 +21,7 @@ export interface OperationInfo { externalDocs?: { url: string; description?: string; - } + }; } @Component({ @@ -56,7 +57,8 @@ export class Operation extends BaseComponent implements OnInit { path: JsonPointer.baseName(this.pointer, 2), info: { description: this.componentSchema.description, - tags: this.filterMainTags(this.componentSchema.tags) + tags: this.filterMainTags(this.componentSchema.tags), + permissions: this.reduceMainPermissions(this.componentSchema['x-permissions']) }, bodyParam: this.findBodyParam(), summary: SchemaHelper.operationSummary(this.componentSchema), @@ -77,6 +79,17 @@ export class Operation extends BaseComponent implements OnInit { return tags.filter(tag => tagsMap[tag] && tagsMap[tag]['x-traitTag']); } + reduceMainPermissions(permissions) { + var permissionsMap = this.specMgr.getPermissionsMap(); + if (!permissions) return []; + return permissions.reduce(( filtered, permission) => { + if( permissionsMap[permission.name] ) { + filtered.push(permissionsMap[permission.name]); + } + return filtered; + }, []); + } + findBodyParam():SwaggerBodyParameter { let params = this.specMgr.getOperationParams(this.pointer); let bodyParam = params.find(param => param.in === 'body'); diff --git a/lib/components/Permissions/x-permissions.html b/lib/components/Permissions/x-permissions.html new file mode 100644 index 00000000..dc6916a2 --- /dev/null +++ b/lib/components/Permissions/x-permissions.html @@ -0,0 +1,5 @@ + diff --git a/lib/components/Permissions/x-permissions.scss b/lib/components/Permissions/x-permissions.scss new file mode 100644 index 00000000..2d2a1da8 --- /dev/null +++ b/lib/components/Permissions/x-permissions.scss @@ -0,0 +1,36 @@ +@import '../../shared/styles/variables'; + +:host { + display: block; +} + +.security-definition:not(:last-of-type) { + border-bottom: 1px solid rgba($text-color, .3); + padding-bottom: 20px; +} + +:host h2 { + padding-top: $section-spacing; +} + +h3 { + margin: 1em 0; + font-size: 1em; +} + +:host .security-scopes-details, :host .security-details { + margin-top: 20px; +} + +table.details th, table.details td { + font-weight: bold; + width: 200px; + max-width: 50%; +} + +table.details th { + text-align: left; + padding: 6px; + text-transform: capitalize; + font-weight: normal; +} diff --git a/lib/components/Permissions/x-permissions.ts b/lib/components/Permissions/x-permissions.ts new file mode 100644 index 00000000..588a1dd8 --- /dev/null +++ b/lib/components/Permissions/x-permissions.ts @@ -0,0 +1,48 @@ +'use strict'; +import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { SpecManager, BaseComponent } from '../base'; + +import { ComponentParser } from '../../services/component-parser.service'; + + + +@Component({ + selector: 'x-permissions', + styleUrls: ['./x-permissions.css'], + templateUrl: './x-permissions.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class XPermissions extends BaseComponent implements OnInit { + info: any = {}; + specUrl: String; + defs: any[]; + + static insertTagIntoDescription(md:string) { + if (ComponentParser.contains(md, 'x-permissions')) return md; + if (/^#\s?Permissions\s*$/mi.test(md)) return md; + return md + '\n\n# Permissions \n' + ComponentParser.build('x-permissions'); + } + + constructor(specMgr:SpecManager) { + super(specMgr); + } + + init() { + this.componentSchema = this.componentSchema['x-permissions']; + this.defs = Object.keys(this.componentSchema).map(name => { + let details = this.componentSchema[name]; + let title = details.title ? details.title : name; + details.description = details.description ? details.description : 'none'; + return { + name, + title, + details + }; + }); + + } + + ngOnInit() { + this.preinit(); + } +} diff --git a/lib/components/SchemaSample/schema-sample.html b/lib/components/SchemaSample/schema-sample.html index f18d57e2..baaa3055 100644 --- a/lib/components/SchemaSample/schema-sample.html +++ b/lib/components/SchemaSample/schema-sample.html @@ -23,7 +23,7 @@ -