@budibase/server 1.0.6 → 1.0.8-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/builder/assets/{index.4fb3f887.css → index.9337c392.css} +1 -1
- package/builder/assets/{index.8b07ec4f.js → index.db2ce927.js} +160 -160
- package/builder/assets/{vendor.470042a4.js → vendor.a9288856.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +369 -330
- package/coverage/coverage-final.json +11 -10
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +14 -14
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +9 -24
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +126 -0
- package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +150 -24
- package/coverage/lcov-report/api/controllers/query/validation.js.html +200 -0
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +5 -2
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +15 -15
- package/coverage/lcov-report/api/controllers/view/index.js.html +52 -10
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +9 -9
- package/coverage/lcov-report/api/routes/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +11 -98
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/row.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/static.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/automations/utils.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/client.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +4 -4
- package/coverage/lcov-report/db/utils.js.html +58 -58
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +55 -40
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/authorized.js.html +2 -2
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +1 -1
- package/coverage/lcov-report/threads/index.js.html +1 -1
- package/coverage/lcov-report/threads/query.js.html +1 -1
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +19 -10
- package/coverage/lcov-report/utilities/global.js.html +1 -1
- package/coverage/lcov-report/utilities/index.html +14 -14
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +1 -1
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +538 -480
- package/dist/api/controllers/query/import/index.js +79 -0
- package/dist/api/controllers/query/import/sources/base/index.js +63 -0
- package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
- package/dist/api/controllers/query/import/sources/curl.js +90 -0
- package/dist/api/controllers/query/import/sources/openapi2.js +139 -0
- package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
- package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
- package/dist/api/controllers/{query.js → query/index.js} +38 -4
- package/dist/api/controllers/query/validation.js +36 -0
- package/dist/api/controllers/view/index.js +15 -2
- package/dist/api/routes/query.js +2 -32
- package/dist/package.json +8 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/csvParser.js +5 -2
- package/package.json +9 -5
- package/src/api/controllers/query/import/index.ts +85 -0
- package/src/api/controllers/query/import/sources/base/index.ts +86 -0
- package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
- package/src/api/controllers/query/import/sources/curl.ts +94 -0
- package/src/api/controllers/query/import/sources/openapi2.ts +159 -0
- package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +104 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +239 -0
- package/src/api/controllers/query/import/tests/index.spec.js +115 -0
- package/src/api/controllers/{query.js → query/index.js} +46 -4
- package/src/api/controllers/query/validation.js +40 -0
- package/src/api/controllers/table/utils.js +1 -0
- package/src/api/controllers/view/index.js +16 -2
- package/src/api/routes/query.js +5 -34
- package/src/definitions/common.ts +22 -0
- package/src/integrations/oracle.ts +1 -1
- package/src/utilities/csvParser.js +5 -2
|
@@ -103,8 +103,11 @@ function transform({ schema, csvString, existingTable }) {
|
|
|
103
103
|
if (existingTable) {
|
|
104
104
|
schema = updateSchema({ schema, existingTable });
|
|
105
105
|
}
|
|
106
|
-
for (let key of Object.
|
|
107
|
-
|
|
106
|
+
for (let [key, field] of Object.entries(schema)) {
|
|
107
|
+
// don't import data to auto columns
|
|
108
|
+
if (!field.autocolumn) {
|
|
109
|
+
colParser[key] = PARSERS[field.type] || field.type;
|
|
110
|
+
}
|
|
108
111
|
}
|
|
109
112
|
try {
|
|
110
113
|
const data = yield csv({ colParser }).fromString(csvString);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.8-alpha.2",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -69,9 +69,10 @@
|
|
|
69
69
|
"author": "Budibase",
|
|
70
70
|
"license": "GPL-3.0",
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@
|
|
73
|
-
"@budibase/
|
|
74
|
-
"@budibase/
|
|
72
|
+
"@apidevtools/swagger-parser": "^10.0.3",
|
|
73
|
+
"@budibase/auth": "^1.0.8-alpha.2",
|
|
74
|
+
"@budibase/client": "^1.0.8-alpha.2",
|
|
75
|
+
"@budibase/string-templates": "^1.0.8-alpha.2",
|
|
75
76
|
"@bull-board/api": "^3.7.0",
|
|
76
77
|
"@bull-board/koa": "^3.7.0",
|
|
77
78
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -85,12 +86,14 @@
|
|
|
85
86
|
"bull": "^3.22.4",
|
|
86
87
|
"chmodr": "1.2.0",
|
|
87
88
|
"csvtojson": "2.0.10",
|
|
89
|
+
"curlconverter": "^3.21.0",
|
|
88
90
|
"dotenv": "8.2.0",
|
|
89
91
|
"download": "8.0.0",
|
|
90
92
|
"fix-path": "3.0.0",
|
|
91
93
|
"fs-extra": "8.1.0",
|
|
92
94
|
"jimp": "0.16.1",
|
|
93
95
|
"joi": "17.2.1",
|
|
96
|
+
"js-yaml": "^4.1.0",
|
|
94
97
|
"jsonschema": "1.4.0",
|
|
95
98
|
"knex": "^0.95.6",
|
|
96
99
|
"koa": "2.7.0",
|
|
@@ -146,6 +149,7 @@
|
|
|
146
149
|
"eslint": "^6.8.0",
|
|
147
150
|
"jest": "^27.0.5",
|
|
148
151
|
"nodemon": "^2.0.4",
|
|
152
|
+
"openapi-types": "^9.3.1",
|
|
149
153
|
"path-to-regexp": "^6.2.0",
|
|
150
154
|
"prettier": "^2.3.1",
|
|
151
155
|
"rimraf": "^3.0.2",
|
|
@@ -158,5 +162,5 @@
|
|
|
158
162
|
"optionalDependencies": {
|
|
159
163
|
"oracledb": "^5.3.0"
|
|
160
164
|
},
|
|
161
|
-
"gitHead": "
|
|
165
|
+
"gitHead": "cc8b159e1124eec08661697ae70c61c1b12b78b7"
|
|
162
166
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import CouchDB from "../../../../db"
|
|
2
|
+
import { queryValidation } from "../validation"
|
|
3
|
+
import { generateQueryID } from "../../../../db/utils"
|
|
4
|
+
import { ImportInfo, ImportSource } from "./sources/base"
|
|
5
|
+
import { OpenAPI2 } from "./sources/openapi2"
|
|
6
|
+
import { Query } from './../../../../definitions/common';
|
|
7
|
+
import { Curl } from "./sources/curl"
|
|
8
|
+
interface ImportResult {
|
|
9
|
+
errorQueries: Query[]
|
|
10
|
+
queries: Query[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class RestImporter {
|
|
14
|
+
data: string
|
|
15
|
+
sources: ImportSource[]
|
|
16
|
+
source!: ImportSource
|
|
17
|
+
|
|
18
|
+
constructor(data: string) {
|
|
19
|
+
this.data = data
|
|
20
|
+
this.sources = [new OpenAPI2(), new Curl()]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
init = async () => {
|
|
24
|
+
for (let source of this.sources) {
|
|
25
|
+
if (await source.isSupported(this.data)) {
|
|
26
|
+
this.source = source
|
|
27
|
+
break
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getInfo = async (): Promise<ImportInfo> => {
|
|
33
|
+
return this.source.getInfo()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
importQueries = async (
|
|
37
|
+
appId: string,
|
|
38
|
+
datasourceId: string
|
|
39
|
+
): Promise<ImportResult> => {
|
|
40
|
+
// constuct the queries
|
|
41
|
+
let queries = await this.source.getQueries(datasourceId)
|
|
42
|
+
|
|
43
|
+
// validate queries
|
|
44
|
+
const errorQueries: Query[] = []
|
|
45
|
+
const schema = queryValidation()
|
|
46
|
+
queries = queries
|
|
47
|
+
.filter(query => {
|
|
48
|
+
const validation = schema.validate(query)
|
|
49
|
+
if (validation.error) {
|
|
50
|
+
errorQueries.push(query)
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
return true
|
|
54
|
+
})
|
|
55
|
+
.map(query => {
|
|
56
|
+
query._id = generateQueryID(query.datasourceId)
|
|
57
|
+
return query
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// persist queries
|
|
61
|
+
const db = new CouchDB(appId)
|
|
62
|
+
const response = await db.bulkDocs(queries)
|
|
63
|
+
|
|
64
|
+
// create index to seperate queries and errors
|
|
65
|
+
const queryIndex = queries.reduce((acc, query) => {
|
|
66
|
+
if (query._id) {
|
|
67
|
+
acc[query._id] = query
|
|
68
|
+
}
|
|
69
|
+
return acc
|
|
70
|
+
}, {} as { [key: string]: Query })
|
|
71
|
+
|
|
72
|
+
// check for failed writes
|
|
73
|
+
response.forEach((query: any) => {
|
|
74
|
+
if (!query.ok) {
|
|
75
|
+
errorQueries.push(queryIndex[query.id])
|
|
76
|
+
delete queryIndex[query.id]
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
errorQueries,
|
|
82
|
+
queries: Object.values(queryIndex),
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
|
|
2
|
+
import { Query, QueryParameter } from "../../../../../../definitions/common"
|
|
3
|
+
|
|
4
|
+
export interface ImportInfo {
|
|
5
|
+
url: string
|
|
6
|
+
name: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
enum MethodToVerb {
|
|
10
|
+
get = "read",
|
|
11
|
+
post = "create",
|
|
12
|
+
put = "update",
|
|
13
|
+
patch = "patch",
|
|
14
|
+
delete = "delete",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export abstract class ImportSource {
|
|
18
|
+
abstract isSupported(data: string): Promise<boolean>
|
|
19
|
+
abstract getInfo(): Promise<ImportInfo>
|
|
20
|
+
abstract getQueries(datasourceId: string): Promise<Query[]>
|
|
21
|
+
|
|
22
|
+
constructQuery = (
|
|
23
|
+
datasourceId: string,
|
|
24
|
+
name: string,
|
|
25
|
+
method: string,
|
|
26
|
+
path: string,
|
|
27
|
+
queryString: string,
|
|
28
|
+
headers: object = {},
|
|
29
|
+
parameters: QueryParameter[] = [],
|
|
30
|
+
body: object | undefined = undefined
|
|
31
|
+
): Query => {
|
|
32
|
+
const readable = true
|
|
33
|
+
const queryVerb = this.verbFromMethod(method)
|
|
34
|
+
const transformer = "return data"
|
|
35
|
+
const schema = {}
|
|
36
|
+
path = this.processPath(path)
|
|
37
|
+
queryString = this.processQuery(queryString)
|
|
38
|
+
const requestBody = JSON.stringify(body, null, 2)
|
|
39
|
+
|
|
40
|
+
const query: Query = {
|
|
41
|
+
datasourceId,
|
|
42
|
+
name,
|
|
43
|
+
parameters,
|
|
44
|
+
fields: {
|
|
45
|
+
headers,
|
|
46
|
+
queryString,
|
|
47
|
+
path,
|
|
48
|
+
requestBody,
|
|
49
|
+
},
|
|
50
|
+
transformer,
|
|
51
|
+
schema,
|
|
52
|
+
readable,
|
|
53
|
+
queryVerb,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return query
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
verbFromMethod = (method: string) => {
|
|
60
|
+
const verb = (<any>MethodToVerb)[method]
|
|
61
|
+
if (!verb) {
|
|
62
|
+
throw new Error(`Unsupported method: ${method}`)
|
|
63
|
+
}
|
|
64
|
+
return verb
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
processPath = (path: string): string => {
|
|
68
|
+
if (path?.startsWith("/")) {
|
|
69
|
+
path = path.substring(1)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// add extra braces around params for binding
|
|
73
|
+
path = path.replace(/[{]/g, "{{")
|
|
74
|
+
path = path.replace(/[}]/g, "}}")
|
|
75
|
+
|
|
76
|
+
return path
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
processQuery = (queryString: string): string => {
|
|
80
|
+
if (queryString?.startsWith("?")) {
|
|
81
|
+
return queryString.substring(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return queryString
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ImportSource } from "."
|
|
2
|
+
import SwaggerParser from "@apidevtools/swagger-parser"
|
|
3
|
+
import { OpenAPI } from "openapi-types"
|
|
4
|
+
const yaml = require("js-yaml")
|
|
5
|
+
|
|
6
|
+
export abstract class OpenAPISource extends ImportSource {
|
|
7
|
+
parseData = async (data: string): Promise<OpenAPI.Document> => {
|
|
8
|
+
let json: OpenAPI.Document
|
|
9
|
+
try {
|
|
10
|
+
json = JSON.parse(data)
|
|
11
|
+
} catch (jsonErr) {
|
|
12
|
+
// couldn't parse json
|
|
13
|
+
// try to convert yaml -> json
|
|
14
|
+
try {
|
|
15
|
+
json = yaml.load(data)
|
|
16
|
+
} catch (yamlErr) {
|
|
17
|
+
// couldn't parse yaml
|
|
18
|
+
throw new Error("Could not parse JSON or YAML")
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return SwaggerParser.validate(json, {})
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ImportSource, ImportInfo } from "./base"
|
|
2
|
+
import { Query } from "../../../../../definitions/common"
|
|
3
|
+
import { URL } from "url"
|
|
4
|
+
const curlconverter = require("curlconverter")
|
|
5
|
+
|
|
6
|
+
const parseCurl = (data: string): any => {
|
|
7
|
+
const curlJson = curlconverter.toJsonString(data)
|
|
8
|
+
return JSON.parse(curlJson)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The curl converter parses the request body into the key field of an object
|
|
13
|
+
* e.g. --d '{"key":"val"}' produces an object { "{"key":"val"}" : "" }
|
|
14
|
+
* This is not what we want, so we need to parse out the key from the object
|
|
15
|
+
*/
|
|
16
|
+
const parseBody = (curl: any) => {
|
|
17
|
+
if (curl.data) {
|
|
18
|
+
const keys = Object.keys(curl.data)
|
|
19
|
+
if (keys.length) {
|
|
20
|
+
const key = keys[0]
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(key)
|
|
23
|
+
} catch (e) {
|
|
24
|
+
// do nothing
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const parseCookie = (curl: any) => {
|
|
32
|
+
if (curl.cookies){
|
|
33
|
+
return Object.entries(curl.cookies).reduce((acc, entry) => {
|
|
34
|
+
const [key, value] = entry
|
|
35
|
+
return acc + `${key}=${value}; `
|
|
36
|
+
}, "")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Curl
|
|
44
|
+
* https://curl.se/docs/manpage.html
|
|
45
|
+
*/
|
|
46
|
+
export class Curl extends ImportSource {
|
|
47
|
+
curl: any
|
|
48
|
+
|
|
49
|
+
isSupported = async (data: string): Promise<boolean> => {
|
|
50
|
+
try {
|
|
51
|
+
const curl = parseCurl(data)
|
|
52
|
+
this.curl = curl
|
|
53
|
+
} catch (err) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getInfo = async (): Promise<ImportInfo> => {
|
|
60
|
+
const url = new URL(this.curl.url)
|
|
61
|
+
return {
|
|
62
|
+
url: url.origin,
|
|
63
|
+
name: url.hostname,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getQueries = async (datasourceId: string): Promise<Query[]> => {
|
|
68
|
+
const url = new URL(this.curl.raw_url)
|
|
69
|
+
const name = url.pathname
|
|
70
|
+
const path = url.pathname
|
|
71
|
+
const method = this.curl.method
|
|
72
|
+
const queryString = url.search
|
|
73
|
+
const headers = this.curl.headers
|
|
74
|
+
const requestBody = parseBody(this.curl)
|
|
75
|
+
|
|
76
|
+
const cookieHeader = parseCookie(this.curl)
|
|
77
|
+
if (cookieHeader) {
|
|
78
|
+
headers["Cookie"] = cookieHeader
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const query = this.constructQuery(
|
|
82
|
+
datasourceId,
|
|
83
|
+
name,
|
|
84
|
+
method,
|
|
85
|
+
path,
|
|
86
|
+
queryString,
|
|
87
|
+
headers,
|
|
88
|
+
[],
|
|
89
|
+
requestBody
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return [query]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { ImportInfo } from "./base"
|
|
2
|
+
import { Query, QueryParameter } from "../../../../../definitions/common"
|
|
3
|
+
import { OpenAPIV2 } from "openapi-types"
|
|
4
|
+
import { OpenAPISource } from "./base/openapi"
|
|
5
|
+
|
|
6
|
+
const parameterNotRef = (
|
|
7
|
+
param: OpenAPIV2.Parameter | OpenAPIV2.ReferenceObject
|
|
8
|
+
): param is OpenAPIV2.Parameter => {
|
|
9
|
+
// all refs are deferenced by parser library
|
|
10
|
+
return true
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const isOpenAPI2 = (document: any): document is OpenAPIV2.Document => {
|
|
14
|
+
if (document.swagger === "2.0") {
|
|
15
|
+
return true
|
|
16
|
+
} else {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const methods: string[] = Object.values(OpenAPIV2.HttpMethods)
|
|
22
|
+
|
|
23
|
+
const isOperation = (
|
|
24
|
+
key: string,
|
|
25
|
+
pathItem: any
|
|
26
|
+
): pathItem is OpenAPIV2.OperationObject => {
|
|
27
|
+
return methods.includes(key)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isParameter = (
|
|
31
|
+
key: string,
|
|
32
|
+
pathItem: any
|
|
33
|
+
): pathItem is OpenAPIV2.Parameter => {
|
|
34
|
+
return !isOperation(key, pathItem)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* OpenAPI Version 2.0 - aka "Swagger"
|
|
39
|
+
* https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md
|
|
40
|
+
*/
|
|
41
|
+
export class OpenAPI2 extends OpenAPISource {
|
|
42
|
+
document!: OpenAPIV2.Document
|
|
43
|
+
|
|
44
|
+
isSupported = async (data: string): Promise<boolean> => {
|
|
45
|
+
try {
|
|
46
|
+
const document: any = await this.parseData(data)
|
|
47
|
+
if (isOpenAPI2(document)) {
|
|
48
|
+
this.document = document
|
|
49
|
+
return true
|
|
50
|
+
} else {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getInfo = async (): Promise<ImportInfo> => {
|
|
59
|
+
const scheme = this.document.schemes?.includes("https") ? "https" : "http"
|
|
60
|
+
const basePath = this.document.basePath || ""
|
|
61
|
+
const host = this.document.host || "<host>"
|
|
62
|
+
const url = `${scheme}://${host}${basePath}`
|
|
63
|
+
const name = this.document.info.title || "Swagger Import"
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
url: url,
|
|
67
|
+
name: name,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getQueries = async (datasourceId: string): Promise<Query[]> => {
|
|
72
|
+
const queries = []
|
|
73
|
+
|
|
74
|
+
for (let [path, pathItem] of Object.entries(this.document.paths)) {
|
|
75
|
+
// parameters that apply to every operation in the path
|
|
76
|
+
let pathParams: OpenAPIV2.Parameter[] = []
|
|
77
|
+
|
|
78
|
+
for (let [key, opOrParams] of Object.entries(pathItem)) {
|
|
79
|
+
if (isParameter(key, opOrParams)) {
|
|
80
|
+
const pathParameters = opOrParams as OpenAPIV2.Parameter[]
|
|
81
|
+
pathParams.push(...pathParameters)
|
|
82
|
+
continue
|
|
83
|
+
}
|
|
84
|
+
// can not be a parameter, must be an operation
|
|
85
|
+
const operation = opOrParams as OpenAPIV2.OperationObject
|
|
86
|
+
|
|
87
|
+
const methodName = key
|
|
88
|
+
const name = operation.operationId || path
|
|
89
|
+
let queryString = ""
|
|
90
|
+
const headers: any = {}
|
|
91
|
+
let requestBody = undefined
|
|
92
|
+
const parameters: QueryParameter[] = []
|
|
93
|
+
|
|
94
|
+
if (operation.consumes) {
|
|
95
|
+
headers["Content-Type"] = operation.consumes[0]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// combine the path parameters with the operation parameters
|
|
99
|
+
const operationParams = operation.parameters || []
|
|
100
|
+
const allParams = [...pathParams, ...operationParams]
|
|
101
|
+
|
|
102
|
+
for (let param of allParams) {
|
|
103
|
+
if (parameterNotRef(param)) {
|
|
104
|
+
switch (param.in) {
|
|
105
|
+
case "query":
|
|
106
|
+
let prefix = ""
|
|
107
|
+
if (queryString) {
|
|
108
|
+
prefix = "&"
|
|
109
|
+
}
|
|
110
|
+
queryString = `${queryString}${prefix}${param.name}={{${param.name}}}`
|
|
111
|
+
break
|
|
112
|
+
case "header":
|
|
113
|
+
headers[param.name] = `{{${param.name}}}`
|
|
114
|
+
break
|
|
115
|
+
case "path":
|
|
116
|
+
// do nothing: param is already in the path
|
|
117
|
+
break
|
|
118
|
+
case "formData":
|
|
119
|
+
// future enhancement
|
|
120
|
+
break
|
|
121
|
+
case "body":
|
|
122
|
+
// set the request body to the example provided
|
|
123
|
+
// future enhancement: generate an example from the schema
|
|
124
|
+
let bodyParam: OpenAPIV2.InBodyParameterObject =
|
|
125
|
+
param as OpenAPIV2.InBodyParameterObject
|
|
126
|
+
if (param.schema.example) {
|
|
127
|
+
const schema = bodyParam.schema as OpenAPIV2.SchemaObject
|
|
128
|
+
requestBody = schema.example
|
|
129
|
+
}
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// add the parameter if it can be bound in our config
|
|
134
|
+
if (["query", "header", "path"].includes(param.in)) {
|
|
135
|
+
parameters.push({
|
|
136
|
+
name: param.name,
|
|
137
|
+
default: param.default || "",
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const query = this.constructQuery(
|
|
144
|
+
datasourceId,
|
|
145
|
+
name,
|
|
146
|
+
methodName,
|
|
147
|
+
path,
|
|
148
|
+
queryString,
|
|
149
|
+
headers,
|
|
150
|
+
parameters,
|
|
151
|
+
requestBody
|
|
152
|
+
)
|
|
153
|
+
queries.push(query)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return queries
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const { Curl } = require("../../curl")
|
|
2
|
+
const fs = require("fs")
|
|
3
|
+
const path = require('path')
|
|
4
|
+
|
|
5
|
+
const getData = (file) => {
|
|
6
|
+
return fs.readFileSync(path.join(__dirname, `./data/${file}.txt`), "utf8")
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe("Curl Import", () => {
|
|
10
|
+
let curl
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
curl = new Curl()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it("validates unsupported data", async () => {
|
|
17
|
+
let data
|
|
18
|
+
let supported
|
|
19
|
+
|
|
20
|
+
// JSON
|
|
21
|
+
data = "{}"
|
|
22
|
+
supported = await curl.isSupported(data)
|
|
23
|
+
expect(supported).toBe(false)
|
|
24
|
+
|
|
25
|
+
// Empty
|
|
26
|
+
data = ""
|
|
27
|
+
supported = await curl.isSupported(data)
|
|
28
|
+
expect(supported).toBe(false)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const init = async (file) => {
|
|
32
|
+
await curl.isSupported(getData(file))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
it("returns import info", async () => {
|
|
36
|
+
await init("get")
|
|
37
|
+
const info = await curl.getInfo()
|
|
38
|
+
expect(info.url).toBe("http://example.com")
|
|
39
|
+
expect(info.name).toBe("example.com")
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe("Returns queries", () => {
|
|
43
|
+
|
|
44
|
+
const getQueries = async (file) => {
|
|
45
|
+
await init(file)
|
|
46
|
+
const queries = await curl.getQueries()
|
|
47
|
+
expect(queries.length).toBe(1)
|
|
48
|
+
return queries
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const testVerb = async (file, verb) => {
|
|
52
|
+
const queries = await getQueries(file)
|
|
53
|
+
expect(queries[0].queryVerb).toBe(verb)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
it("populates verb", async () => {
|
|
57
|
+
await testVerb("get", "read")
|
|
58
|
+
await testVerb("post", "create")
|
|
59
|
+
await testVerb("put", "update")
|
|
60
|
+
await testVerb("delete", "delete")
|
|
61
|
+
await testVerb("patch", "patch")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const testPath = async (file, urlPath) => {
|
|
65
|
+
const queries = await getQueries(file)
|
|
66
|
+
expect(queries[0].fields.path).toBe(urlPath)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
it("populates path", async () => {
|
|
70
|
+
await testPath("get", "")
|
|
71
|
+
await testPath("path", "paths/abc")
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const testHeaders = async (file, headers) => {
|
|
75
|
+
const queries = await getQueries(file)
|
|
76
|
+
expect(queries[0].fields.headers).toStrictEqual(headers)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
it("populates headers", async () => {
|
|
80
|
+
await testHeaders("get", {})
|
|
81
|
+
await testHeaders("headers", { "x-bb-header-1" : "123", "x-bb-header-2" : "456"} )
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const testQuery = async (file, queryString) => {
|
|
85
|
+
const queries = await getQueries(file)
|
|
86
|
+
expect(queries[0].fields.queryString).toBe(queryString)
|
|
87
|
+
}
|
|
88
|
+
it("populates query", async () => {
|
|
89
|
+
await testQuery("get", "")
|
|
90
|
+
await testQuery("query", "q1=v1&q1=v2")
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const testBody = async (file, body) => {
|
|
94
|
+
const queries = await getQueries(file)
|
|
95
|
+
expect(queries[0].fields.requestBody).toStrictEqual(JSON.stringify(body, null, 2))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
it("populates body", async () => {
|
|
99
|
+
await testBody("get", undefined)
|
|
100
|
+
await testBody("post", { "key" : "val" })
|
|
101
|
+
await testBody("empty-body", {})
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
curl -X DELETE 'http://example.com'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
curl 'http://example.com'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
curl 'http://example.com/paths/abc'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
curl 'http://example.com/paths/abc?q1=v1&q1=v2'
|