@budibase/server 0.9.190-alpha.0 → 0.9.190-alpha.12

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.
Files changed (199) hide show
  1. package/builder/assets/{index.7d405e74.css → index.4fb3f887.css} +1 -1
  2. package/builder/assets/{index.43f4c913.js → index.92596167.js} +171 -171
  3. package/builder/index.html +2 -2
  4. package/coverage/clover.xml +381 -390
  5. package/coverage/coverage-final.json +23 -23
  6. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  7. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/application.js.html +62 -80
  9. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/datasource.js.html +15 -15
  15. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +29 -29
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +9 -9
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query.js.html +34 -28
  23. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/routing.js.html +27 -27
  25. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  32. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/index.html +14 -14
  35. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/internal.js.html +8 -20
  37. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  46. package/coverage/lcov-report/api/index.html +1 -1
  47. package/coverage/lcov-report/api/index.js.html +5 -5
  48. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/index.html +1 -1
  61. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/row.js.html +536 -2
  70. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/table.js.html +436 -7
  74. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  78. package/coverage/lcov-report/automations/actions.js.html +1 -1
  79. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  80. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  81. package/coverage/lcov-report/automations/index.html +1 -1
  82. package/coverage/lcov-report/automations/index.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/index.html +1 -1
  92. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  110. package/coverage/lcov-report/automations/utils.js.html +5 -5
  111. package/coverage/lcov-report/constants/index.html +1 -1
  112. package/coverage/lcov-report/constants/index.js.html +1 -1
  113. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  114. package/coverage/lcov-report/constants/screens.js.html +2 -2
  115. package/coverage/lcov-report/db/client.js.html +1 -1
  116. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  117. package/coverage/lcov-report/db/index.html +1 -1
  118. package/coverage/lcov-report/db/index.js.html +1 -1
  119. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  120. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  121. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  122. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  123. package/coverage/lcov-report/db/newid.js.html +2 -2
  124. package/coverage/lcov-report/db/utils.js.html +19 -19
  125. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  126. package/coverage/lcov-report/events/index.html +1 -1
  127. package/coverage/lcov-report/events/index.js.html +1 -1
  128. package/coverage/lcov-report/events/utils.js.html +1 -1
  129. package/coverage/lcov-report/index.html +25 -25
  130. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  131. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  132. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  133. package/coverage/lcov-report/middleware/authorized.js.html +9 -9
  134. package/coverage/lcov-report/middleware/builder.js.html +7 -7
  135. package/coverage/lcov-report/middleware/currentapp.js.html +28 -28
  136. package/coverage/lcov-report/middleware/index.html +1 -1
  137. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  138. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  139. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  140. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  141. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  142. package/coverage/lcov-report/threads/automation.js.html +1 -1
  143. package/coverage/lcov-report/threads/index.html +1 -1
  144. package/coverage/lcov-report/threads/index.js.html +1 -1
  145. package/coverage/lcov-report/threads/query.js.html +1 -1
  146. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  147. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  148. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  149. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  150. package/coverage/lcov-report/utilities/global.js.html +13 -13
  151. package/coverage/lcov-report/utilities/index.html +1 -1
  152. package/coverage/lcov-report/utilities/index.js.html +3 -3
  153. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  154. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  155. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  156. package/coverage/lcov-report/utilities/routing/index.js.html +2 -2
  157. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  158. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  159. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  160. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  161. package/coverage/lcov-report/utilities/security.js.html +1 -1
  162. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  163. package/coverage/lcov-report/utilities/users.js.html +1 -1
  164. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  165. package/coverage/lcov.info +645 -658
  166. package/dist/api/controllers/application.js +1 -5
  167. package/dist/api/controllers/query.js +2 -4
  168. package/dist/api/controllers/row/ExternalRequest.js +46 -22
  169. package/dist/api/controllers/table/internal.js +0 -4
  170. package/dist/api/routes/row.js +178 -0
  171. package/dist/api/routes/table.js +148 -5
  172. package/dist/definitions/datasource.js +12 -1
  173. package/dist/integrations/base/sql.js +30 -15
  174. package/dist/integrations/index.js +1 -1
  175. package/dist/integrations/mysql.js +2 -1
  176. package/dist/integrations/oracle.js +42 -20
  177. package/dist/integrations/utils.js +1 -1
  178. package/dist/package.json +10 -6
  179. package/dist/tsconfig.tsbuildinfo +1 -1
  180. package/package.json +11 -7
  181. package/scripts/docs/README.md +31 -0
  182. package/scripts/docs/generate.js +74 -0
  183. package/scripts/docs/toSwagger.js +320 -0
  184. package/scripts/integrations/oracle/docker-compose.yml +1 -1
  185. package/src/api/controllers/application.js +0 -6
  186. package/src/api/controllers/query.js +6 -4
  187. package/src/api/controllers/row/ExternalRequest.ts +52 -22
  188. package/src/api/controllers/table/internal.js +0 -4
  189. package/src/api/routes/row.js +178 -0
  190. package/src/api/routes/table.js +148 -5
  191. package/src/api/routes/tests/application.spec.js +0 -2
  192. package/src/api/routes/tests/query.spec.js +38 -8
  193. package/src/api/routes/tests/screen.spec.js +1 -1
  194. package/src/definitions/datasource.ts +11 -0
  195. package/src/integrations/base/sql.ts +31 -14
  196. package/src/integrations/index.ts +2 -2
  197. package/src/integrations/mysql.ts +3 -1
  198. package/src/integrations/oracle.ts +43 -24
  199. package/src/integrations/utils.ts +6 -2
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "0.9.190-alpha.0",
4
+ "version": "0.9.190-alpha.12",
5
5
  "description": "Budibase Web Server",
6
- "main": "src/index.js",
6
+ "main": "src/index.ts",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/Budibase/budibase.git"
@@ -15,6 +15,7 @@
15
15
  "test:watch": "jest --watch",
16
16
  "predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client",
17
17
  "build:docker": "yarn run predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION",
18
+ "build:docs": "node ./scripts/docs/generate.js open",
18
19
  "run:docker": "node dist/index.js",
19
20
  "dev:stack:up": "node scripts/dev/manage.js up",
20
21
  "dev:stack:down": "node scripts/dev/manage.js down",
@@ -68,9 +69,9 @@
68
69
  "author": "Budibase",
69
70
  "license": "GPL-3.0",
70
71
  "dependencies": {
71
- "@budibase/auth": "^0.9.190-alpha.0",
72
- "@budibase/client": "^0.9.190-alpha.0",
73
- "@budibase/string-templates": "^0.9.190-alpha.0",
72
+ "@budibase/auth": "^0.9.190-alpha.12",
73
+ "@budibase/client": "^0.9.190-alpha.12",
74
+ "@budibase/string-templates": "^0.9.190-alpha.12",
74
75
  "@bull-board/api": "^3.7.0",
75
76
  "@bull-board/koa": "^3.7.0",
76
77
  "@elastic/elasticsearch": "7.10.0",
@@ -106,7 +107,7 @@
106
107
  "mssql": "6.2.3",
107
108
  "mysql2": "^2.3.1",
108
109
  "node-fetch": "2.6.0",
109
- "open": "7.3.0",
110
+ "open": "^8.4.0",
110
111
  "pg": "8.5.1",
111
112
  "pino-pretty": "4.0.0",
112
113
  "posthog-node": "^1.1.4",
@@ -130,6 +131,7 @@
130
131
  "@babel/preset-env": "^7.14.4",
131
132
  "@budibase/standard-components": "^0.9.139",
132
133
  "@jest/test-sequencer": "^24.8.0",
134
+ "@types/apidoc": "^0.50.0",
133
135
  "@types/bull": "^3.15.1",
134
136
  "@types/jest": "^26.0.23",
135
137
  "@types/koa": "^2.13.3",
@@ -137,12 +139,14 @@
137
139
  "@types/node": "^15.12.4",
138
140
  "@types/oracledb": "^5.2.1",
139
141
  "@typescript-eslint/parser": "4.28.0",
142
+ "apidoc": "^0.50.2",
140
143
  "babel-jest": "^27.0.2",
141
144
  "copyfiles": "^2.4.1",
142
145
  "docker-compose": "^0.23.6",
143
146
  "eslint": "^6.8.0",
144
147
  "jest": "^27.0.5",
145
148
  "nodemon": "^2.0.4",
149
+ "path-to-regexp": "^6.2.0",
146
150
  "prettier": "^2.3.1",
147
151
  "rimraf": "^3.0.2",
148
152
  "supertest": "^4.0.2",
@@ -154,5 +158,5 @@
154
158
  "optionalDependencies": {
155
159
  "oracledb": "^5.3.0"
156
160
  },
157
- "gitHead": "58c1927f6a5dcbab760fbdb9d581b1ef1bb9dabf"
161
+ "gitHead": "4e607feda0a258f486df6fe138940b7faab1db99"
158
162
  }
@@ -0,0 +1,31 @@
1
+ ### Documentation
2
+
3
+ This directory contains the scripts required to generate the APIDoc based documentation.
4
+ You can find the docs about comment structure at the [APIDocs page](https://apidocjs.com/).
5
+
6
+ In general most API endpoints will look like:
7
+ ```js
8
+ /**
9
+ * @api {post} /api/:param/url Give it a name
10
+ * @apiName Give it a name
11
+ * @apiGroup group
12
+ * @apiPermission permission
13
+ * @apiDescription Describe what the endpoint does, any special cases the user
14
+ * should be aware of.
15
+ *
16
+ * @apiParam {string} param describe a URL parameter.
17
+ *
18
+ * @apiParam (Body) input describe a field on the body.
19
+ *
20
+ * @apiSuccess {object} output describe the output.
21
+ */
22
+ ```
23
+
24
+ There are a few key points to note when writing API docs:
25
+ 1. Don't use `@apiBody` - this isn't currently supported by our swagger converter.
26
+ 2. Make sure to always have an `@api` definition at the start, which must always have the
27
+ HTTP verb, the endpoint URL and the name.
28
+ 3. There are three ways you can specify parameters used as inputs for your endpoint,
29
+ `@apiParam` for a URL param, `@apiParam (Body)` for a field on the request body and `@apiParam (Query)`
30
+ for query string parameters.
31
+ 4. The `@apiGroup` should be the same for all API Doc comments in a route file.
@@ -0,0 +1,74 @@
1
+ const fs = require("fs")
2
+ const { join } = require("path")
3
+ const { createDoc } = require("apidoc")
4
+ const packageJson = require("../../package.json")
5
+ const toSwagger = require("./toSwagger")
6
+ const open = require("open")
7
+
8
+ const config = {
9
+ name: "Budibase API",
10
+ version: packageJson.version,
11
+ description: "Documenting the Budibase backend API",
12
+ title: "Budibase app service API",
13
+ }
14
+
15
+ const shouldOpen = process.argv[2]
16
+ const disallowed = []
17
+
18
+ function filter(parsedRouteFiles) {
19
+ const tagToSearch = "url"
20
+ for (let routeFile of parsedRouteFiles) {
21
+ for (let route of routeFile) {
22
+ let routeInfo = route["local"]
23
+ if (disallowed.includes(routeInfo[tagToSearch])) {
24
+ const idx = routeFile.indexOf(route)
25
+ routeFile.splice(idx, 1)
26
+ }
27
+ }
28
+ }
29
+ }
30
+
31
+ async function generate() {
32
+ // start by writing a config file
33
+ const configPath = join(__dirname, "config.json")
34
+ fs.writeFileSync(configPath, JSON.stringify(config))
35
+ const mainPath = join(__dirname, "..", "..")
36
+ const srcPath = join(mainPath, "src", "api", "routes")
37
+ const assetsPath = join(mainPath, "builder", "assets", "docs")
38
+ if (!fs.existsSync(assetsPath)) {
39
+ fs.mkdirSync(assetsPath, { recursive: true })
40
+ }
41
+ const options = {
42
+ src: [srcPath],
43
+ dest: assetsPath,
44
+ filters: {
45
+ main: {
46
+ postFilter: filter,
47
+ },
48
+ },
49
+ config: configPath,
50
+ }
51
+ const doc = createDoc(options)
52
+ if (typeof doc !== "boolean") {
53
+ const swagger = toSwagger(JSON.parse(doc.data), JSON.parse(doc.project))
54
+ fs.writeFileSync(join(assetsPath, "swagger.json"), JSON.stringify(swagger))
55
+ fs.writeFileSync(join(assetsPath, "apidoc.json"), doc.data)
56
+ fs.writeFileSync(join(assetsPath, "project.json"), doc.project)
57
+ console.log(
58
+ `Docs generated successfully, find in ${assetsPath}, swagger.json, apidoc.json and project.json`
59
+ )
60
+ } else {
61
+ throw "Unable to generate docs."
62
+ }
63
+ // delete the temporary config file
64
+ fs.unlinkSync(configPath)
65
+ setTimeout(async () => {
66
+ if (shouldOpen === "open") {
67
+ await open(join(assetsPath, "index.html"), { wait: false })
68
+ }
69
+ }, 2000)
70
+ }
71
+
72
+ generate().catch(err => {
73
+ console.error(err)
74
+ })
@@ -0,0 +1,320 @@
1
+ let _ = require("lodash")
2
+ let { pathToRegexp } = require("path-to-regexp")
3
+
4
+ /********************************************************
5
+ * Based on: https://github.com/fsbahman/apidoc-swagger *
6
+ ********************************************************/
7
+
8
+ let swagger = {
9
+ swagger: "2.0",
10
+ info: {},
11
+ paths: {},
12
+ definitions: {},
13
+ }
14
+
15
+ function toSwagger(apidocJson, projectJson) {
16
+ swagger.info = addInfo(projectJson)
17
+ swagger.paths = extractPaths(apidocJson)
18
+ return swagger
19
+ }
20
+
21
+ let tagsRegex = /(<([^>]+)>)/gi
22
+ // Removes <p> </p> tags from text
23
+ function removeTags(text) {
24
+ return text ? text.replace(tagsRegex, "") : text
25
+ }
26
+
27
+ function addInfo(projectJson) {
28
+ let info = {}
29
+ info["title"] = projectJson.title || projectJson.name
30
+ info["version"] = projectJson.version
31
+ info["description"] = projectJson.description
32
+ return info
33
+ }
34
+
35
+ /**
36
+ * Extracts paths provided in json format
37
+ * post, patch, put request parameters are extracted in body
38
+ * get and delete are extracted to path parameters
39
+ * @param apidocJson
40
+ * @returns {{}}
41
+ */
42
+ function extractPaths(apidocJson) {
43
+ let apiPaths = groupByUrl(apidocJson)
44
+ let paths = {}
45
+ for (let i = 0; i < apiPaths.length; i++) {
46
+ let verbs = apiPaths[i].verbs
47
+ let url = verbs[0].url
48
+ let pattern = pathToRegexp(url, null)
49
+ let matches = pattern.exec(url)
50
+
51
+ // Surrounds URL parameters with curly brackets -> :email with {email}
52
+ let pathKeys = []
53
+ for (let j = 1; j < matches.length; j++) {
54
+ let key = matches[j].substr(1)
55
+ url = url.replace(matches[j], "{" + key + "}")
56
+ pathKeys.push(key)
57
+ }
58
+
59
+ for (let j = 0; j < verbs.length; j++) {
60
+ let verb = verbs[j]
61
+ let type = verb.type
62
+
63
+ let obj = (paths[url] = paths[url] || {})
64
+
65
+ if (type === "post" || type === "patch" || type === "put") {
66
+ _.extend(
67
+ obj,
68
+ createPostPushPutOutput(verb, swagger.definitions, pathKeys)
69
+ )
70
+ } else {
71
+ _.extend(obj, createGetDeleteOutput(verb, swagger.definitions))
72
+ }
73
+ }
74
+ }
75
+ return paths
76
+ }
77
+
78
+ function createPostPushPutOutput(verbs, definitions, pathKeys) {
79
+ let pathItemObject = {}
80
+ let verbDefinitionResult = createVerbDefinitions(verbs, definitions)
81
+
82
+ let params = []
83
+ let pathParams = createPathParameters(verbs, pathKeys)
84
+ pathParams = _.filter(pathParams, function (param) {
85
+ let hasKey = pathKeys.indexOf(param.name) !== -1
86
+ return !(param.in === "path" && !hasKey)
87
+ })
88
+
89
+ params = params.concat(pathParams)
90
+ let required =
91
+ verbs.parameter &&
92
+ verbs.parameter.fields &&
93
+ verbs.parameter.fields.Parameter &&
94
+ verbs.parameter.fields.Parameter.length > 0
95
+
96
+ params.push({
97
+ in: "body",
98
+ name: "body",
99
+ description: removeTags(verbs.description),
100
+ required: required,
101
+ schema: {
102
+ $ref: "#/definitions/" + verbDefinitionResult.topLevelParametersRef,
103
+ },
104
+ })
105
+
106
+ pathItemObject[verbs.type] = {
107
+ tags: [verbs.group],
108
+ summary: removeTags(verbs.description),
109
+ consumes: ["application/json"],
110
+ produces: ["application/json"],
111
+ parameters: params,
112
+ }
113
+
114
+ if (verbDefinitionResult.topLevelSuccessRef) {
115
+ pathItemObject[verbs.type].responses = {
116
+ 200: {
117
+ description: "successful operation",
118
+ schema: {
119
+ type: verbDefinitionResult.topLevelSuccessRefType,
120
+ items: {
121
+ $ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef,
122
+ },
123
+ },
124
+ },
125
+ }
126
+ }
127
+
128
+ return pathItemObject
129
+ }
130
+
131
+ function createVerbDefinitions(verbs, definitions) {
132
+ let result = {
133
+ topLevelParametersRef: null,
134
+ topLevelSuccessRef: null,
135
+ topLevelSuccessRefType: null,
136
+ }
137
+ let defaultObjectName = verbs.name
138
+
139
+ let fieldArrayResult = {}
140
+ if (verbs && verbs.parameter && verbs.parameter.fields) {
141
+ fieldArrayResult = createFieldArrayDefinitions(
142
+ verbs.parameter.fields.Parameter,
143
+ definitions,
144
+ verbs.name,
145
+ defaultObjectName
146
+ )
147
+ result.topLevelParametersRef = fieldArrayResult.topLevelRef
148
+ }
149
+
150
+ if (verbs && verbs.success && verbs.success.fields) {
151
+ fieldArrayResult = createFieldArrayDefinitions(
152
+ verbs.success.fields["Success 200"],
153
+ definitions,
154
+ verbs.name,
155
+ defaultObjectName
156
+ )
157
+ result.topLevelSuccessRef = fieldArrayResult.topLevelRef
158
+ result.topLevelSuccessRefType = fieldArrayResult.topLevelRefType
159
+ }
160
+
161
+ return result
162
+ }
163
+
164
+ function createFieldArrayDefinitions(
165
+ fieldArray,
166
+ definitions,
167
+ topLevelRef,
168
+ defaultObjectName
169
+ ) {
170
+ let result = {
171
+ topLevelRef: topLevelRef,
172
+ topLevelRefType: null,
173
+ }
174
+
175
+ if (!fieldArray) {
176
+ return result
177
+ }
178
+
179
+ for (let i = 0; i < fieldArray.length; i++) {
180
+ let parameter = fieldArray[i]
181
+
182
+ let nestedName = createNestedName(parameter.field)
183
+ let objectName = nestedName.objectName
184
+ if (!objectName) {
185
+ objectName = defaultObjectName
186
+ }
187
+ let type = parameter.type
188
+ if (i === 0) {
189
+ result.topLevelRefType = type
190
+ if (parameter.type === "Object") {
191
+ objectName = nestedName.propertyName
192
+ nestedName.propertyName = null
193
+ } else if (parameter.type === "Array") {
194
+ objectName = nestedName.propertyName
195
+ nestedName.propertyName = null
196
+ result.topLevelRefType = "array"
197
+ }
198
+ result.topLevelRef = objectName
199
+ }
200
+
201
+ definitions[objectName] = definitions[objectName] || {
202
+ properties: {},
203
+ required: [],
204
+ }
205
+
206
+ if (nestedName.propertyName) {
207
+ let prop = {
208
+ type: (parameter.type || "").toLowerCase(),
209
+ description: removeTags(parameter.description),
210
+ }
211
+ if (parameter.type === "Object") {
212
+ prop.$ref = "#/definitions/" + parameter.field
213
+ }
214
+
215
+ let typeIndex = type.indexOf("[]")
216
+ if (typeIndex !== -1 && typeIndex === type.length - 2) {
217
+ prop.type = "array"
218
+ prop.items = {
219
+ type: type.slice(0, type.length - 2),
220
+ }
221
+ }
222
+
223
+ definitions[objectName]["properties"][nestedName.propertyName] = prop
224
+ if (!parameter.optional) {
225
+ let arr = definitions[objectName]["required"]
226
+ if (arr.indexOf(nestedName.propertyName) === -1) {
227
+ arr.push(nestedName.propertyName)
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ return result
234
+ }
235
+
236
+ function createNestedName(field) {
237
+ let propertyName = field
238
+ let objectName
239
+ let propertyNames = field.split(".")
240
+ if (propertyNames && propertyNames.length > 1) {
241
+ propertyName = propertyNames[propertyNames.length - 1]
242
+ propertyNames.pop()
243
+ objectName = propertyNames.join(".")
244
+ }
245
+
246
+ return {
247
+ propertyName: propertyName,
248
+ objectName: objectName,
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Generate get, delete method output
254
+ * @param verbs
255
+ * @param definitions
256
+ * @returns {{}}
257
+ */
258
+ function createGetDeleteOutput(verbs, definitions) {
259
+ let pathItemObject = {}
260
+ verbs.type = verbs.type === "del" ? "delete" : verbs.type
261
+
262
+ let verbDefinitionResult = createVerbDefinitions(verbs, definitions)
263
+ pathItemObject[verbs.type] = {
264
+ tags: [verbs.group],
265
+ summary: removeTags(verbs.description),
266
+ consumes: ["application/json"],
267
+ produces: ["application/json"],
268
+ parameters: createPathParameters(verbs),
269
+ }
270
+ if (verbDefinitionResult.topLevelSuccessRef) {
271
+ pathItemObject[verbs.type].responses = {
272
+ 200: {
273
+ description: "successful operation",
274
+ schema: {
275
+ type: verbDefinitionResult.topLevelSuccessRefType,
276
+ items: {
277
+ $ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef,
278
+ },
279
+ },
280
+ },
281
+ }
282
+ }
283
+ return pathItemObject
284
+ }
285
+
286
+ /**
287
+ * Iterate through all method parameters and create array of parameter objects which are stored as path parameters
288
+ * @param verbs
289
+ * @returns {Array}
290
+ */
291
+ function createPathParameters(verbs) {
292
+ let pathItemObject = []
293
+ if (verbs.parameter && verbs.parameter.fields.Parameter) {
294
+ for (let i = 0; i < verbs.parameter.fields.Parameter.length; i++) {
295
+ let param = verbs.parameter.fields.Parameter[i]
296
+ let field = param.field
297
+ let type = param.type
298
+ pathItemObject.push({
299
+ name: field,
300
+ in: type === "file" ? "formData" : "path",
301
+ required: !param.optional,
302
+ type: param.type.toLowerCase(),
303
+ description: removeTags(param.description),
304
+ })
305
+ }
306
+ }
307
+ return pathItemObject
308
+ }
309
+
310
+ function groupByUrl(apidocJson) {
311
+ return _.chain(apidocJson)
312
+ .groupBy("url")
313
+ .toPairs()
314
+ .map(function (element) {
315
+ return _.zipObject(["url", "verbs"], element)
316
+ })
317
+ .value()
318
+ }
319
+
320
+ module.exports = toSwagger
@@ -4,7 +4,7 @@
4
4
  version: "3.8"
5
5
  services:
6
6
  db:
7
- container_name: oracle-xe
7
+ restart: always
8
8
  platform: linux/x86_64
9
9
  image: container-registry.oracle.com/database/express:18.4.0-xe
10
10
  environment:
@@ -15,14 +15,12 @@ const {
15
15
  generateAppID,
16
16
  getLayoutParams,
17
17
  getScreenParams,
18
- generateScreenID,
19
18
  generateDevAppID,
20
19
  DocumentTypes,
21
20
  AppStatus,
22
21
  } = require("../../db/utils")
23
22
  const { BUILTIN_ROLE_IDS, AccessController } = require("@budibase/auth/roles")
24
23
  const { BASE_LAYOUTS } = require("../../constants/layouts")
25
- const { createHomeScreen } = require("../../constants/screens")
26
24
  const { cloneDeep } = require("lodash/fp")
27
25
  const { processObject } = require("@budibase/string-templates")
28
26
  const {
@@ -409,9 +407,5 @@ const createEmptyAppPackage = async (ctx, app) => {
409
407
  screensAndLayouts.push(await processObject(cloned, app))
410
408
  }
411
409
 
412
- const homeScreen = createHomeScreen(app)
413
- homeScreen._id = generateScreenID()
414
- screensAndLayouts.push(homeScreen)
415
-
416
410
  await db.bulkDocs(screensAndLayouts)
417
411
  }
@@ -1,8 +1,11 @@
1
1
  const { processString } = require("@budibase/string-templates")
2
2
  const CouchDB = require("../../db")
3
- const { generateQueryID, getQueryParams } = require("../../db/utils")
3
+ const {
4
+ generateQueryID,
5
+ getQueryParams,
6
+ isProdAppID,
7
+ } = require("../../db/utils")
4
8
  const { BaseQueryVerbs } = require("../../constants")
5
- const env = require("../../environment")
6
9
  const { Thread, ThreadType } = require("../../threads")
7
10
 
8
11
  const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
@@ -90,10 +93,9 @@ exports.find = async function (ctx) {
90
93
  const db = new CouchDB(ctx.appId)
91
94
  const query = enrichQueries(await db.get(ctx.params.queryId))
92
95
  // remove properties that could be dangerous in real app
93
- if (env.isProd()) {
96
+ if (isProdAppID(ctx.appId)) {
94
97
  delete query.fields
95
98
  delete query.parameters
96
- delete query.schema
97
99
  }
98
100
  ctx.body = query
99
101
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ FilterTypes,
2
3
  IncludeRelationships,
3
4
  Operation,
4
5
  PaginationJson,
@@ -118,8 +119,13 @@ module External {
118
119
  }
119
120
  // check the row and filters to make sure they aren't a key of some sort
120
121
  if (config.filters) {
121
- for (let filter of Object.values(config.filters)) {
122
- if (typeof filter !== "object" || Object.keys(filter).length === 0) {
122
+ for (let [key, filter] of Object.entries(config.filters)) {
123
+ // oneOf is an array, don't iterate it
124
+ if (
125
+ typeof filter !== "object" ||
126
+ Object.keys(filter).length === 0 ||
127
+ key === FilterTypes.ONE_OF
128
+ ) {
123
129
  continue
124
130
  }
125
131
  iterateObject(filter)
@@ -197,9 +203,9 @@ module External {
197
203
  return row
198
204
  }
199
205
 
200
- function isMany(field: FieldSchema) {
206
+ function isOneSide(field: FieldSchema) {
201
207
  return (
202
- field.relationshipType && field.relationshipType.split("-")[0] === "many"
208
+ field.relationshipType && field.relationshipType.split("-")[0] === "one"
203
209
  )
204
210
  }
205
211
 
@@ -274,25 +280,37 @@ module External {
274
280
  const linkTable = this.tables[linkTableName]
275
281
  // @ts-ignore
276
282
  const linkTablePrimary = linkTable.primary[0]
277
- if (!isMany(field)) {
283
+ // one to many
284
+ if (isOneSide(field)) {
278
285
  newRow[field.foreignKey || linkTablePrimary] = breakRowIdField(
279
286
  row[key][0]
280
287
  )[0]
281
- } else {
288
+ }
289
+ // many to many
290
+ else if (field.through) {
282
291
  // we're not inserting a doc, will be a bunch of update calls
283
- const isUpdate = !field.through
284
- const thisKey: string = isUpdate
285
- ? "id"
286
- : field.throughTo || linkTablePrimary
287
- // @ts-ignore
288
- const otherKey: string = isUpdate
289
- ? field.fieldName
290
- : field.throughFrom || tablePrimary
292
+ const otherKey: string = field.throughFrom || linkTablePrimary
293
+ const thisKey: string = field.throughTo || tablePrimary
291
294
  row[key].map((relationship: any) => {
292
- // we don't really support composite keys for relationships, this is why [0] is used
293
295
  manyRelationships.push({
294
296
  tableId: field.through || field.tableId,
295
- isUpdate,
297
+ isUpdate: false,
298
+ key: otherKey,
299
+ [otherKey]: breakRowIdField(relationship)[0],
300
+ // leave the ID for enrichment later
301
+ [thisKey]: `{{ literal ${tablePrimary} }}`,
302
+ })
303
+ })
304
+ }
305
+ // many to one
306
+ else {
307
+ const thisKey: string = "id"
308
+ // @ts-ignore
309
+ const otherKey: string = field.fieldName
310
+ row[key].map((relationship: any) => {
311
+ manyRelationships.push({
312
+ tableId: field.tableId,
313
+ isUpdate: true,
296
314
  key: otherKey,
297
315
  [thisKey]: breakRowIdField(relationship)[0],
298
316
  // leave the ID for enrichment later
@@ -425,8 +443,8 @@ module External {
425
443
  )
426
444
  definition.through = throughTableName
427
445
  // don't support composite keys for relationships
428
- definition.from = field.throughFrom || table.primary[0]
429
- definition.to = field.throughTo || linkTable.primary[0]
446
+ definition.from = field.throughTo || table.primary[0]
447
+ definition.to = field.throughFrom || linkTable.primary[0]
430
448
  definition.fromPrimary = table.primary[0]
431
449
  definition.toPrimary = linkTable.primary[0]
432
450
  }
@@ -448,24 +466,36 @@ module External {
448
466
  // make a new request to get the row with all its relationships
449
467
  // we need this to work out if any relationships need removed
450
468
  for (let field of Object.values(table.schema)) {
451
- if (field.type !== FieldTypes.LINK || !field.fieldName) {
469
+ if (
470
+ field.type !== FieldTypes.LINK ||
471
+ !field.fieldName ||
472
+ isOneSide(field)
473
+ ) {
452
474
  continue
453
475
  }
454
476
  const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY
455
477
  const tableId = isMany ? field.through : field.tableId
456
- const manyKey = field.throughFrom || primaryKey
478
+ const { tableName: relatedTableName } = breakExternalTableId(tableId)
479
+ // @ts-ignore
480
+ const linkPrimaryKey = this.tables[relatedTableName].primary[0]
481
+ const manyKey = field.throughTo || primaryKey
482
+ const lookupField = isMany ? primaryKey : field.foreignKey
457
483
  const fieldName = isMany ? manyKey : field.fieldName
484
+ if (!lookupField || !row[lookupField]) {
485
+ continue
486
+ }
458
487
  const response = await getDatasourceAndQuery(this.appId, {
459
488
  endpoint: getEndpoint(tableId, DataSourceOperation.READ),
460
489
  filters: {
461
490
  equal: {
462
- [fieldName]: row[primaryKey],
491
+ [fieldName]: row[lookupField],
463
492
  },
464
493
  },
465
494
  })
466
495
  // this is the response from knex if no rows found
467
496
  const rows = !response[0].read ? response : []
468
- related[fieldName] = { rows, isMany, tableId }
497
+ const storeTo = isMany ? field.throughFrom || linkPrimaryKey : manyKey
498
+ related[storeTo] = { rows, isMany, tableId }
469
499
  }
470
500
  return related
471
501
  }