Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7d39036
Added tooling for appending OAS3 relative URLs to selected Server
May 2, 2019
95bf267
Merge branch 'master' into fix/oas3-relative-urls
May 3, 2019
619cbfe
Modified buildUrl util to append realtive URLs beginning with '/' to …
May 3, 2019
ebef288
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Jun 23, 2020
4fe710a
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Jul 3, 2020
9d43142
Removed erroroneous exclamations marks!
geraldglynn Jul 3, 2020
79d61e4
Updated varibale to `termsOfServiceUrl`
geraldglynn Jul 3, 2020
e218574
Changed how externalDocs url & description are retrieved and named
geraldglynn Jul 3, 2020
1c5b39b
Changed naming of `tagExternalDocsUrl`
geraldglynn Jul 3, 2020
2518603
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Jul 20, 2020
b44ac98
Added unit test for util `isAbsoluteUrl()`
geraldglynn Jul 20, 2020
2852fb1
Added unit tests for util `buildUrl()`
geraldglynn Jul 20, 2020
74c252e
Cleaned up utils `buildUrl()` to use URL class for constructing URL
geraldglynn Jul 21, 2020
d0887a9
Improved unit test for utils `buildUrl()`
geraldglynn Jul 21, 2020
2228717
Removed unused `fromJS` and cleaned up whitespace
geraldglynn Jul 21, 2020
111af62
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Jul 21, 2020
a170d64
Added support for server relative urls in utils `buildUrl()`
geraldglynn Jul 22, 2020
e526ef4
Cleaned up `buildUrl` unit tests and added `location.href` to window.…
geraldglynn Jul 22, 2020
9fd7f39
Replaced `app.swaggerhub.com` with `example.com`
geraldglynn Jul 23, 2020
2e62a08
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Jul 23, 2020
e9c91f4
Fixed whitespacing in mocha test `utils.js`
geraldglynn Jul 23, 2020
2d427e0
Added guard to `externalDocs` in <Info />
geraldglynn Jul 23, 2020
c7390ed
Commented out `location.href` in window.js; it was breaking another test
geraldglynn Jul 23, 2020
b47d397
Added extra check to utils `buildUrl()`
geraldglynn Jul 23, 2020
a1edf30
Added `selectedServer` to test mock props
geraldglynn Jul 23, 2020
8ac390b
Skipped test "build url from server with relative url"
geraldglynn Jul 23, 2020
4e69e75
Removed "location" from window.js `props`
geraldglynn Jul 24, 2020
40493da
Added specUrl to buildUrl to support relative server url or no server…
geraldglynn Jul 24, 2020
80b8438
Added unit tests for `buildBaseUrl()` and improved unit tests `isAbso…
geraldglynn Jul 24, 2020
53cad46
Added utils `addProtocol()`
geraldglynn Jul 24, 2020
795355e
Removed `console.log()` from utils
geraldglynn Jul 27, 2020
0632862
Add PropTypes `url`
geraldglynn Jul 27, 2020
867b0aa
Added `specSelector.url()` to mock props for unit test
geraldglynn Jul 27, 2020
86e9af7
Merge branch 'master' into fix/oas3-relative-urls
tim-lai Jul 29, 2020
3c6cf6e
Merge branch 'master' into fix/oas3-relative-urls
geraldglynn Aug 4, 2020
9206b7e
Merge branch 'fix/oas3-relative-urls' of https://github.com/geraldgly…
geraldglynn Aug 4, 2020
cba7b4f
Moved new url util functions to `utils/url`
geraldglynn Aug 4, 2020
89b8d1a
style: Update test/mocha/core/utils.js
tim-lai Aug 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions src/core/components/info.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
import { sanitizeUrl } from "core/utils"
import { buildUrl } from "core/utils/url"


export class InfoBasePath extends React.Component {
Expand All @@ -26,13 +26,16 @@ export class InfoBasePath extends React.Component {
class Contact extends React.Component {
static propTypes = {
data: PropTypes.object,
getComponent: PropTypes.func.isRequired
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
selectedServer: PropTypes.string,
url: PropTypes.string.isRequired,
}

render(){
let { data, getComponent } = this.props
let { data, getComponent, selectedServer, url: specUrl} = this.props
let name = data.get("name") || "the developer"
let url = data.get("url")
let url = buildUrl(data.get("url"), specUrl, {selectedServer})
let email = data.get("email")

const Link = getComponent("Link")
Expand All @@ -53,17 +56,18 @@ class Contact extends React.Component {
class License extends React.Component {
static propTypes = {
license: PropTypes.object,
getComponent: PropTypes.func.isRequired

getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
selectedServer: PropTypes.string,
url: PropTypes.string.isRequired,
}

render(){
let { license, getComponent } = this.props
let { license, getComponent, selectedServer, url: specUrl } = this.props

const Link = getComponent("Link")

let name = license.get("name") || "License"
let url = license.get("url")
let name = license.get("name") || "License"
let url = buildUrl(license.get("url"), specUrl, {selectedServer})

return (
<div className="info__license">
Expand All @@ -88,7 +92,7 @@ export class InfoUrl extends React.PureComponent {

const Link = getComponent("Link")

return <Link target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url } </span></Link>
return <Link target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url }</span></Link>
}
}

Expand All @@ -100,17 +104,21 @@ export default class Info extends React.Component {
basePath: PropTypes.string,
externalDocs: ImPropTypes.map,
getComponent: PropTypes.func.isRequired,
oas3selectors: PropTypes.func,
selectedServer: PropTypes.string,
}

render() {
let { info, url, host, basePath, getComponent, externalDocs } = this.props
let { info, url, host, basePath, getComponent, externalDocs, selectedServer, url: specUrl } = this.props
let version = info.get("version")
let description = info.get("description")
let title = info.get("title")
let termsOfService = info.get("termsOfService")
let termsOfServiceUrl = buildUrl(info.get("termsOfService"), specUrl, {selectedServer})
Copy link

@marcelstoer marcelstoer Jan 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a breaking change for us. Our OAS2 documents have inline termsOfService rather than a URL e.g.

termsOfService: 'Information in this document is subject to change ...'

Contrary to OAS 3 with OAS2 it is not required for the termsOfService to be a URL (as per https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-1). Hence, before building this URL the termsOfService value should first be verified to be a URL.

let contact = info.get("contact")
let license = info.get("license")
const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()
let rawExternalDocsUrl = externalDocs && externalDocs.get("url")
let externalDocsUrl = buildUrl(rawExternalDocsUrl, specUrl, {selectedServer})
let externalDocsDescription = externalDocs && externalDocs.get("description")

const Markdown = getComponent("Markdown", true)
const Link = getComponent("Link")
Expand All @@ -133,14 +141,14 @@ export default class Info extends React.Component {
</div>

{
termsOfService && <div className="info__tos">
<Link target="_blank" href={ sanitizeUrl(termsOfService) }>Terms of service</Link>
termsOfServiceUrl && <div className="info__tos">
<Link target="_blank" href={ sanitizeUrl(termsOfServiceUrl) }>Terms of service</Link>
</div>
}

{contact && contact.size ? <Contact getComponent={getComponent} data={ contact } /> : null }
{license && license.size ? <License getComponent={getComponent} license={ license } /> : null }
{ externalDocsUrl ?
{contact && contact.size ? <Contact getComponent={getComponent} data={ contact } selectedServer={selectedServer} url={url} /> : null }
{license && license.size ? <License getComponent={getComponent} license={ license } selectedServer={selectedServer} url={url}/> : null }
{ externalDocs ?
<Link className="info__extdocs" target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
: null }

Expand Down
10 changes: 8 additions & 2 deletions src/core/components/operation-tag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import Im from "immutable"
import { createDeepLinkPath, escapeDeepLinkPath, sanitizeUrl } from "core/utils"
import { buildUrl } from "core/utils/url"

export default class OperationTag extends React.Component {

Expand All @@ -15,12 +16,15 @@ export default class OperationTag extends React.Component {
tagObj: ImPropTypes.map.isRequired,
tag: PropTypes.string.isRequired,

oas3Selectors: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,

getConfigs: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,

specUrl: PropTypes.string.isRequired,

children: PropTypes.element,
}

Expand All @@ -29,11 +33,12 @@ export default class OperationTag extends React.Component {
tagObj,
tag,
children,

oas3Selectors,
layoutSelectors,
layoutActions,
getConfigs,
getComponent,
specUrl,
} = this.props

let {
Expand All @@ -50,7 +55,8 @@ export default class OperationTag extends React.Component {

let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
let rawTagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
let tagExternalDocsUrl = buildUrl( rawTagExternalDocsUrl, specUrl, {selectedServer: oas3Selectors.selectedServer()} )

let isShownKey = ["operations-tag", tag]
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
Expand Down
6 changes: 4 additions & 2 deletions src/core/components/operation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { getList } from "core/utils"
import { getExtensions, sanitizeUrl, escapeDeepLinkPath } from "core/utils"
import { buildUrl } from "core/utils/url"
import { Iterable, List } from "immutable"
import ImPropTypes from "react-immutable-proptypes"

Expand Down Expand Up @@ -81,6 +82,7 @@ export default class Operation extends PureComponent {
schemes
} = op

const externalDocsUrl = externalDocs ? buildUrl(externalDocs.url, specSelectors.url(), { selectedServer: oas3Selectors.selectedServer() }) : ""
let operation = operationProps.getIn(["op"])
let responses = operation.get("responses")
let parameters = getList(operation, ["parameters"])
Expand Down Expand Up @@ -127,14 +129,14 @@ export default class Operation extends PureComponent {
</div>
}
{
externalDocs && externalDocs.url ?
externalDocsUrl ?
<div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs">
<span className="opblock-external-docs__description">
<Markdown source={ externalDocs.description } />
</span>
<Link target="_blank" className="opblock-external-docs__link" href={sanitizeUrl(externalDocs.url)}>{externalDocs.url}</Link>
<Link target="_blank" className="opblock-external-docs__link" href={sanitizeUrl(externalDocsUrl)}>{externalDocsUrl}</Link>
</div>
</div> : null
}
Expand Down
6 changes: 5 additions & 1 deletion src/core/components/operations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default class Operations extends React.Component {
specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
oas3Selectors: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
Expand All @@ -28,6 +29,7 @@ export default class Operations extends React.Component {
let {
specSelectors,
getComponent,
oas3Selectors,
layoutSelectors,
layoutActions,
getConfigs,
Expand Down Expand Up @@ -65,10 +67,12 @@ export default class Operations extends React.Component {
key={"operation-" + tag}
tagObj={tagObj}
tag={tag}
oas3Selectors={oas3Selectors}
layoutSelectors={layoutSelectors}
layoutActions={layoutActions}
getConfigs={getConfigs}
getComponent={getComponent}>
getComponent={getComponent}
specUrl={specSelectors.url()}>
{
operations.map( op => {
const path = op.get("path")
Expand Down
6 changes: 4 additions & 2 deletions src/core/containers/info.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ export default class InfoContainer extends React.Component {
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
oas3Selectors: PropTypes.func.isRequired,
}

render () {
const {specSelectors, getComponent} = this.props
const {specSelectors, getComponent, oas3Selectors} = this.props

const info = specSelectors.info()
const url = specSelectors.url()
const basePath = specSelectors.basePath()
const host = specSelectors.host()
const externalDocs = specSelectors.externalDocs()
const selectedServer = oas3Selectors.selectedServer()

const Info = getComponent("info")

return (
<div>
{info && info.count() ? (
<Info info={info} url={url} host={host} basePath={basePath} externalDocs={externalDocs}
getComponent={getComponent}/>
getComponent={getComponent} selectedServer={selectedServer} />
) : null}
</div>
)
Expand Down
5 changes: 2 additions & 3 deletions src/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ export const validatePattern = (val, rxPattern) => {

// validation of parameters before execute
export const validateParam = (param, value, { isOAS3 = false, bypassRequiredCheck = false } = {}) => {

let errors = []

let paramRequired = param.get("required")
Expand Down Expand Up @@ -436,7 +436,7 @@ export const validateParam = (param, value, { isOAS3 = false, bypassRequiredChec
let objectStringCheck = type === "object" && typeof value === "string" && value

const allChecks = [
stringCheck, arrayCheck, arrayListCheck, arrayStringCheck, fileCheck,
stringCheck, arrayCheck, arrayListCheck, arrayStringCheck, fileCheck,
booleanCheck, numberCheck, integerCheck, objectCheck, objectStringCheck,
]

Expand Down Expand Up @@ -640,7 +640,6 @@ export function sanitizeUrl(url) {
return braintreeSanitizeUrl(url)
}


export function requiresValidationURL(uri) {
if (!uri || uri.indexOf("localhost") >= 0 || uri.indexOf("127.0.0.1") >= 0 || uri === "none") {
return false
Expand Down
23 changes: 23 additions & 0 deletions src/core/utils/url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export function isAbsoluteUrl(url) {
return url.match(/^(?:[a-z]+:)?\/\//i) // Matches http://, HTTP://, https://, ftp://, //example.com,
}

export function addProtocol(url) {
if(!url.match(/^\/\//i)) return url // Checks if protocol is missing e.g. //example.com
return `${window.location.protocol}${url}`
}

export function buildBaseUrl(selectedServer, specUrl) {
if(!selectedServer) return specUrl
if(isAbsoluteUrl(selectedServer)) return addProtocol(selectedServer)

return new URL(selectedServer, specUrl).href
}

export function buildUrl(url, specUrl, { selectedServer="" } = {}) {
if(!url) return
if(isAbsoluteUrl(url)) return url

const baseUrl = buildBaseUrl(selectedServer, specUrl)
return new URL(url, baseUrl).href
}
5 changes: 4 additions & 1 deletion test/mocha/components/info-wrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ describe("<InfoContainer/>", function () {
url () {},
basePath () {},
host () {},
externalDocs () {}
externalDocs () {},
},
oas3Selectors: {
selectedServer () {},
},
getComponent: c => components[c]
}
Expand Down
2 changes: 2 additions & 0 deletions test/mocha/components/operations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe("<Operations/>", function(){
},
specSelectors: {
isOAS3() { return false },
url() { return "https://petstore.swagger.io/v2/swagger.json" },
taggedOperations() {
return fromJS({
"default": {
Expand Down Expand Up @@ -83,6 +84,7 @@ describe("<Operations/>", function(){
},
specSelectors: {
isOAS3() { return true },
url() { return "https://petstore.swagger.io/v2/swagger.json" },
taggedOperations() {
return fromJS({
"default": {
Expand Down
Loading