@budibase/server 1.0.25 → 1.0.27-alpha.10

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 (255) hide show
  1. package/__mocks__/node-fetch.ts +21 -0
  2. package/builder/assets/bb-spaceship.8f6e81e1.svg +227 -0
  3. package/builder/assets/{index.4fb3f887.css → index.0dce895b.css} +1 -1
  4. package/builder/assets/index.39751e34.js +1348 -0
  5. package/builder/assets/{vendor.470042a4.js → vendor.f9faf6ab.js} +88 -88
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +1263 -1036
  8. package/coverage/coverage-final.json +36 -35
  9. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/application.js.html +54 -54
  12. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/automation.js.html +22 -10
  14. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  17. package/coverage/lcov-report/api/controllers/datasource.js.html +62 -62
  18. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/index.html +39 -54
  21. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/query/index.html +126 -0
  26. package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +225 -114
  27. package/coverage/lcov-report/api/controllers/query/validation.js.html +206 -0
  28. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/index.html +22 -22
  32. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/row/internal.js.html +38 -11
  34. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +7 -4
  35. package/coverage/lcov-report/api/controllers/row/utils.js.html +29 -20
  36. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +108 -9
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +18 -6
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +5 -5
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/index.html +9 -9
  66. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +19 -85
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +32 -2
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +1 -1
  84. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  85. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  86. package/coverage/lcov-report/automations/index.html +20 -20
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +31 -7
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/index.html +11 -11
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +5 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  114. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  115. package/coverage/lcov-report/automations/utils.js.html +48 -15
  116. package/coverage/lcov-report/constants/index.html +1 -1
  117. package/coverage/lcov-report/constants/index.js.html +22 -22
  118. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  119. package/coverage/lcov-report/constants/screens.js.html +1 -1
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  125. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +107 -80
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +1 -1
  133. package/coverage/lcov-report/events/utils.js.html +1 -1
  134. package/coverage/lcov-report/index.html +99 -84
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +10 -10
  139. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  140. package/coverage/lcov-report/middleware/currentapp.js.html +28 -28
  141. package/coverage/lcov-report/middleware/index.html +1 -1
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +11 -11
  143. package/coverage/lcov-report/middleware/resourceId.js.html +17 -17
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  146. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +31 -31
  149. package/coverage/lcov-report/threads/index.js.html +11 -11
  150. package/coverage/lcov-report/threads/query.js.html +394 -67
  151. package/coverage/lcov-report/threads/utils.js.html +356 -11
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  154. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  155. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  156. package/coverage/lcov-report/utilities/global.js.html +13 -13
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +68 -35
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +19 -19
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +235 -10
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  167. package/coverage/lcov-report/utilities/security.js.html +2 -2
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/users.js.html +1 -1
  170. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  171. package/coverage/lcov.info +2117 -1728
  172. package/dist/api/controllers/automation.js +7 -5
  173. package/dist/api/controllers/query/import/index.js +79 -0
  174. package/dist/api/controllers/query/import/sources/base/index.js +64 -0
  175. package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
  176. package/dist/api/controllers/query/import/sources/curl.js +96 -0
  177. package/dist/api/controllers/query/import/sources/openapi2.js +142 -0
  178. package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  179. package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  180. package/dist/api/controllers/{query.js → query/index.js} +86 -52
  181. package/dist/api/controllers/query/validation.js +38 -0
  182. package/dist/api/controllers/row/internal.js +14 -6
  183. package/dist/api/controllers/row/internalSearch.js +2 -1
  184. package/dist/api/controllers/row/utils.js +13 -6
  185. package/dist/api/controllers/user.js +37 -1
  186. package/dist/api/controllers/webhook.js +4 -0
  187. package/dist/api/routes/query.js +5 -33
  188. package/dist/api/routes/user.js +3 -1
  189. package/dist/automations/steps/executeQuery.js +8 -1
  190. package/dist/automations/steps/outgoingWebhook.js +2 -3
  191. package/dist/automations/utils.js +10 -0
  192. package/dist/db/utils.js +8 -0
  193. package/dist/definitions/datasource.js +6 -1
  194. package/dist/integrations/base/sqlTable.js +1 -1
  195. package/dist/integrations/rest.js +207 -117
  196. package/dist/package.json +11 -4
  197. package/dist/tests/utilities/TestConfiguration.js +7 -0
  198. package/dist/threads/query.js +148 -40
  199. package/dist/threads/utils.js +105 -0
  200. package/dist/tsconfig.tsbuildinfo +1 -1
  201. package/dist/utilities/fileSystem/utilities.js +2 -1
  202. package/dist/utilities/index.js +10 -0
  203. package/dist/utilities/rowProcessor/index.js +76 -0
  204. package/package.json +12 -5
  205. package/src/api/controllers/automation.js +8 -4
  206. package/src/api/controllers/query/import/index.ts +85 -0
  207. package/src/api/controllers/query/import/sources/base/index.ts +87 -0
  208. package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
  209. package/src/api/controllers/query/import/sources/curl.ts +102 -0
  210. package/src/api/controllers/query/import/sources/openapi2.ts +163 -0
  211. package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +103 -0
  212. package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
  213. package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
  214. package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
  215. package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
  216. package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
  217. package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
  218. package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
  219. package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
  220. package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
  221. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  222. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
  223. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  224. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
  225. package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +238 -0
  226. package/src/api/controllers/query/import/tests/index.spec.js +109 -0
  227. package/src/api/controllers/query/index.js +195 -0
  228. package/src/api/controllers/query/validation.js +42 -0
  229. package/src/api/controllers/row/internal.js +14 -5
  230. package/src/api/controllers/row/internalSearch.js +2 -1
  231. package/src/api/controllers/row/utils.js +11 -8
  232. package/src/api/controllers/user.js +33 -0
  233. package/src/api/controllers/webhook.js +4 -0
  234. package/src/api/routes/query.js +13 -35
  235. package/src/api/routes/tests/query.spec.js +88 -0
  236. package/src/api/routes/user.js +10 -0
  237. package/src/automations/steps/executeQuery.js +9 -1
  238. package/src/automations/steps/outgoingWebhook.js +2 -3
  239. package/src/automations/utils.js +11 -0
  240. package/src/db/utils.js +9 -0
  241. package/src/definitions/common.ts +2 -16
  242. package/src/definitions/datasource.ts +83 -1
  243. package/src/integrations/base/IntegrationBase.ts +4 -4
  244. package/src/integrations/base/sqlTable.ts +1 -1
  245. package/src/integrations/oracle.ts +1 -1
  246. package/src/integrations/rest.ts +230 -137
  247. package/src/integrations/tests/rest.spec.js +167 -19
  248. package/src/tests/utilities/TestConfiguration.js +10 -0
  249. package/src/threads/query.js +149 -40
  250. package/src/threads/utils.js +115 -0
  251. package/src/utilities/fileSystem/utilities.js +2 -0
  252. package/src/utilities/index.js +11 -0
  253. package/src/utilities/rowProcessor/index.js +75 -0
  254. package/builder/assets/index.f01106f0.js +0 -1316
  255. package/src/api/controllers/query.js +0 -158
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const { ObjectStore, makeSureBucketExists, upload, streamUpload, retrieve, retrieveToTmp, deleteFolder, uploadDirectory, downloadTarball, } = require("@budibase/auth").objectStore;
2
+ const { ObjectStore, makeSureBucketExists, upload, deleteFiles, streamUpload, retrieve, retrieveToTmp, deleteFolder, uploadDirectory, downloadTarball, } = require("@budibase/auth").objectStore;
3
3
  /***********************************
4
4
  * NOTE *
5
5
  * This file purely exists so that *
@@ -17,3 +17,4 @@ exports.retrieveToTmp = retrieveToTmp;
17
17
  exports.deleteFolder = deleteFolder;
18
18
  exports.uploadDirectory = uploadDirectory;
19
19
  exports.downloadTarball = downloadTarball;
20
+ exports.deleteFiles = deleteFiles;
@@ -142,3 +142,13 @@ exports.doesDatabaseExist = (dbName) => __awaiter(void 0, void 0, void 0, functi
142
142
  return false;
143
143
  }
144
144
  });
145
+ exports.formatBytes = bytes => {
146
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
147
+ const byteIncrements = 1024;
148
+ let unit = 0;
149
+ let size = parseInt(bytes, 10) || 0;
150
+ while (size >= byteIncrements && ++unit) {
151
+ size /= byteIncrements;
152
+ }
153
+ return `${size.toFixed(size < 10 && unit > 0 ? 1 : 0)}${units[unit]}`;
154
+ };
@@ -13,6 +13,10 @@ const { cloneDeep } = require("lodash/fp");
13
13
  const { FieldTypes, AutoFieldSubTypes } = require("../../constants");
14
14
  const { attachmentsRelativeURL } = require("../index");
15
15
  const { processFormulas } = require("./utils");
16
+ const { deleteFiles } = require("../../utilities/fileSystem/utilities");
17
+ const { ObjectStoreBuckets } = require("../../constants");
18
+ const { isProdAppID, getDeployedAppID, dbExists } = require("@budibase/auth/db");
19
+ const CouchDB = require("../../db");
16
20
  const BASE_AUTO_ID = 1;
17
21
  /**
18
22
  * A map of how we convert various properties in rows to each other based on the row type.
@@ -89,7 +93,36 @@ const TYPE_TRANSFORM_MAP = {
89
93
  [FieldTypes.AUTO]: {
90
94
  parse: () => undefined,
91
95
  },
96
+ [FieldTypes.JSON]: {
97
+ parse: input => {
98
+ try {
99
+ if (input === "") {
100
+ return undefined;
101
+ }
102
+ return JSON.parse(input);
103
+ }
104
+ catch (err) {
105
+ return input;
106
+ }
107
+ },
108
+ },
92
109
  };
110
+ /**
111
+ * Given the old state of the row and the new one after an update, this will
112
+ * find the keys that have been removed in the updated row.
113
+ */
114
+ function getRemovedAttachmentKeys(oldRow, row, attachmentKey) {
115
+ if (!oldRow[attachmentKey]) {
116
+ return [];
117
+ }
118
+ const oldKeys = oldRow[attachmentKey].map(attachment => attachment.key);
119
+ // no attachments in new row, all removed
120
+ if (!row[attachmentKey]) {
121
+ return oldKeys;
122
+ }
123
+ const newKeys = row[attachmentKey].map(attachment => attachment.key);
124
+ return oldKeys.filter(key => newKeys.indexOf(key) === -1);
125
+ }
93
126
  /**
94
127
  * This will update any auto columns that are found on the row/table with the correct information based on
95
128
  * time now and the current logged in user making the request.
@@ -240,3 +273,46 @@ exports.outputProcessing = (ctx, table, rows, opts = { squash: true }) => __awai
240
273
  }
241
274
  return wasArray ? enriched : enriched[0];
242
275
  });
276
+ /**
277
+ * Clean up any attachments that were attached to a row.
278
+ * @param {string} appId The ID of the app from which a row is being deleted.
279
+ * @param {object} table The table from which a row is being removed.
280
+ * @param {any} row optional - the row being removed.
281
+ * @param {any} rows optional - if multiple rows being deleted can do this in bulk.
282
+ * @param {any} oldRow optional - if updating a row this will determine the difference.
283
+ * @return {Promise<void>} When all attachments have been removed this will return.
284
+ */
285
+ exports.cleanupAttachments = (appId, table, { row, rows, oldRow }) => __awaiter(void 0, void 0, void 0, function* () {
286
+ if (!isProdAppID(appId)) {
287
+ const prodAppId = getDeployedAppID(appId);
288
+ // if prod exists, then don't allow deleting
289
+ const exists = yield dbExists(CouchDB, prodAppId);
290
+ if (exists) {
291
+ return;
292
+ }
293
+ }
294
+ let files = [];
295
+ function addFiles(row, key) {
296
+ if (row[key]) {
297
+ files = files.concat(row[key].map(attachment => attachment.key));
298
+ }
299
+ }
300
+ for (let [key, schema] of Object.entries(table.schema)) {
301
+ if (schema.type !== FieldTypes.ATTACHMENT) {
302
+ continue;
303
+ }
304
+ // if updating, need to manage the differences
305
+ if (oldRow && row) {
306
+ files = files.concat(getRemovedAttachmentKeys(oldRow, row, key));
307
+ }
308
+ else if (row) {
309
+ addFiles(row, key);
310
+ }
311
+ else if (rows) {
312
+ rows.forEach(row => addFiles(row, key));
313
+ }
314
+ }
315
+ if (files.length > 0) {
316
+ return deleteFiles(ObjectStoreBuckets.APPS, files);
317
+ }
318
+ });
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.25",
4
+ "version": "1.0.27-alpha.10",
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
- "@budibase/auth": "^1.0.25",
73
- "@budibase/client": "^1.0.25",
74
- "@budibase/string-templates": "^1.0.25",
72
+ "@apidevtools/swagger-parser": "^10.0.3",
73
+ "@budibase/auth": "^1.0.27-alpha.10",
74
+ "@budibase/client": "^1.0.27-alpha.10",
75
+ "@budibase/string-templates": "^1.0.27-alpha.10",
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,15 @@
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",
93
+ "form-data": "^4.0.0",
91
94
  "fs-extra": "8.1.0",
92
95
  "jimp": "0.16.1",
93
96
  "joi": "17.2.1",
97
+ "js-yaml": "^4.1.0",
94
98
  "jsonschema": "1.4.0",
95
99
  "knex": "^0.95.6",
96
100
  "koa": "2.7.0",
@@ -118,11 +122,13 @@
118
122
  "pouchdb-replication-stream": "1.2.9",
119
123
  "server-destroy": "1.0.1",
120
124
  "svelte": "^3.38.2",
125
+ "swagger-parser": "^10.0.3",
121
126
  "to-json-schema": "0.2.5",
122
127
  "uuid": "3.3.2",
123
128
  "validate.js": "0.13.1",
124
129
  "vm2": "^3.9.3",
125
130
  "worker-farm": "^1.7.0",
131
+ "xml2js": "^0.4.23",
126
132
  "yargs": "13.2.4",
127
133
  "zlib": "1.0.5"
128
134
  },
@@ -146,6 +152,7 @@
146
152
  "eslint": "^6.8.0",
147
153
  "jest": "^27.0.5",
148
154
  "nodemon": "^2.0.4",
155
+ "openapi-types": "^9.3.1",
149
156
  "path-to-regexp": "^6.2.0",
150
157
  "prettier": "^2.3.1",
151
158
  "rimraf": "^3.0.2",
@@ -158,5 +165,5 @@
158
165
  "optionalDependencies": {
159
166
  "oracledb": "^5.3.0"
160
167
  },
161
- "gitHead": "382b86689a90ef561bd06d9020ee3d1400052d19"
168
+ "gitHead": "37b3e81a0d6f99566d3b753f79b91d5b05185106"
162
169
  }
@@ -5,11 +5,15 @@ const { getAutomationParams, generateAutomationID } = require("../../db/utils")
5
5
  const {
6
6
  checkForWebhooks,
7
7
  updateTestHistory,
8
+ removeDeprecated,
8
9
  } = require("../../automations/utils")
9
10
  const { deleteEntityMetadata } = require("../../utilities")
10
11
  const { MetadataTypes } = require("../../constants")
11
12
  const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
12
13
 
14
+ const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
15
+ const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
16
+
13
17
  /*************************
14
18
  * *
15
19
  * BUILDER FUNCTIONS *
@@ -155,17 +159,17 @@ exports.destroy = async function (ctx) {
155
159
  }
156
160
 
157
161
  exports.getActionList = async function (ctx) {
158
- ctx.body = actions.ACTION_DEFINITIONS
162
+ ctx.body = ACTION_DEFS
159
163
  }
160
164
 
161
165
  exports.getTriggerList = async function (ctx) {
162
- ctx.body = triggers.TRIGGER_DEFINITIONS
166
+ ctx.body = TRIGGER_DEFS
163
167
  }
164
168
 
165
169
  module.exports.getDefinitionList = async function (ctx) {
166
170
  ctx.body = {
167
- trigger: triggers.TRIGGER_DEFINITIONS,
168
- action: actions.ACTION_DEFINITIONS,
171
+ trigger: TRIGGER_DEFS,
172
+ action: ACTION_DEFS,
169
173
  }
170
174
  }
171
175
 
@@ -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,87 @@
1
+ import { Query, QueryParameter } from "../../../../../../definitions/datasource"
2
+ import { URL } from "url"
3
+
4
+ export interface ImportInfo {
5
+ name: string
6
+ }
7
+
8
+ enum MethodToVerb {
9
+ get = "read",
10
+ post = "create",
11
+ put = "update",
12
+ patch = "patch",
13
+ delete = "delete",
14
+ }
15
+
16
+ export abstract class ImportSource {
17
+ abstract isSupported(data: string): Promise<boolean>
18
+ abstract getInfo(): Promise<ImportInfo>
19
+ abstract getQueries(datasourceId: string): Promise<Query[]>
20
+
21
+ constructQuery = (
22
+ datasourceId: string,
23
+ name: string,
24
+ method: string,
25
+ path: string,
26
+ url: URL,
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
+ path = `${url.origin}/${path}`
38
+ queryString = this.processQuery(queryString)
39
+ const requestBody = JSON.stringify(body, null, 2)
40
+
41
+ const query: Query = {
42
+ datasourceId,
43
+ name,
44
+ parameters,
45
+ fields: {
46
+ headers,
47
+ queryString,
48
+ path,
49
+ requestBody,
50
+ },
51
+ transformer,
52
+ schema,
53
+ readable,
54
+ queryVerb,
55
+ }
56
+
57
+ return query
58
+ }
59
+
60
+ verbFromMethod = (method: string) => {
61
+ const verb = (<any>MethodToVerb)[method]
62
+ if (!verb) {
63
+ throw new Error(`Unsupported method: ${method}`)
64
+ }
65
+ return verb
66
+ }
67
+
68
+ processPath = (path: string): string => {
69
+ if (path?.startsWith("/")) {
70
+ path = path.substring(1)
71
+ }
72
+
73
+ // add extra braces around params for binding
74
+ path = path.replace(/[{]/g, "{{")
75
+ path = path.replace(/[}]/g, "}}")
76
+
77
+ return path
78
+ }
79
+
80
+ processQuery = (queryString: string): string => {
81
+ if (queryString?.startsWith("?")) {
82
+ return queryString.substring(1)
83
+ }
84
+
85
+ return queryString
86
+ }
87
+ }
@@ -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,102 @@
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
+ let key = keys[0]
21
+ try {
22
+ // filter out the dollar syntax used by curl for shell support
23
+ if (key.startsWith("$")) {
24
+ key = key.substring(1)
25
+ }
26
+ return JSON.parse(key)
27
+ } catch (e) {
28
+ // do nothing
29
+ }
30
+ }
31
+ }
32
+ return undefined
33
+ }
34
+
35
+ const parseCookie = (curl: any) => {
36
+ if (curl.cookies) {
37
+ return Object.entries(curl.cookies).reduce((acc, entry) => {
38
+ const [key, value] = entry
39
+ return acc + `${key}=${value}; `
40
+ }, "")
41
+ }
42
+
43
+ return null
44
+ }
45
+
46
+ /**
47
+ * Curl
48
+ * https://curl.se/docs/manpage.html
49
+ */
50
+ export class Curl extends ImportSource {
51
+ curl: any
52
+
53
+ isSupported = async (data: string): Promise<boolean> => {
54
+ try {
55
+ const curl = parseCurl(data)
56
+ this.curl = curl
57
+ } catch (err) {
58
+ return false
59
+ }
60
+ return true
61
+ }
62
+
63
+ getUrl = (): URL => {
64
+ return new URL(this.curl.raw_url)
65
+ }
66
+
67
+ getInfo = async (): Promise<ImportInfo> => {
68
+ const url = this.getUrl()
69
+ return {
70
+ name: url.hostname,
71
+ }
72
+ }
73
+
74
+ getQueries = async (datasourceId: string): Promise<Query[]> => {
75
+ const url = this.getUrl()
76
+ const name = url.pathname
77
+ const path = url.pathname
78
+ const method = this.curl.method
79
+ const queryString = url.search
80
+ const headers = this.curl.headers
81
+ const requestBody = parseBody(this.curl)
82
+
83
+ const cookieHeader = parseCookie(this.curl)
84
+ if (cookieHeader) {
85
+ headers["Cookie"] = cookieHeader
86
+ }
87
+
88
+ const query = this.constructQuery(
89
+ datasourceId,
90
+ name,
91
+ method,
92
+ path,
93
+ url,
94
+ queryString,
95
+ headers,
96
+ [],
97
+ requestBody
98
+ )
99
+
100
+ return [query]
101
+ }
102
+ }
@@ -0,0 +1,163 @@
1
+ import { ImportInfo } from "./base"
2
+ import { Query, QueryParameter } from "../../../../../definitions/datasource"
3
+ import { OpenAPIV2 } from "openapi-types"
4
+ import { OpenAPISource } from "./base/openapi"
5
+ import { URL } from "url"
6
+
7
+ const parameterNotRef = (
8
+ param: OpenAPIV2.Parameter | OpenAPIV2.ReferenceObject
9
+ ): param is OpenAPIV2.Parameter => {
10
+ // all refs are deferenced by parser library
11
+ return true
12
+ }
13
+
14
+ const isOpenAPI2 = (document: any): document is OpenAPIV2.Document => {
15
+ if (document.swagger === "2.0") {
16
+ return true
17
+ } else {
18
+ return false
19
+ }
20
+ }
21
+
22
+ const methods: string[] = Object.values(OpenAPIV2.HttpMethods)
23
+
24
+ const isOperation = (
25
+ key: string,
26
+ pathItem: any
27
+ ): pathItem is OpenAPIV2.OperationObject => {
28
+ return methods.includes(key)
29
+ }
30
+
31
+ const isParameter = (
32
+ key: string,
33
+ pathItem: any
34
+ ): pathItem is OpenAPIV2.Parameter => {
35
+ return !isOperation(key, pathItem)
36
+ }
37
+
38
+ /**
39
+ * OpenAPI Version 2.0 - aka "Swagger"
40
+ * https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md
41
+ */
42
+ export class OpenAPI2 extends OpenAPISource {
43
+ document!: OpenAPIV2.Document
44
+
45
+ isSupported = async (data: string): Promise<boolean> => {
46
+ try {
47
+ const document: any = await this.parseData(data)
48
+ if (isOpenAPI2(document)) {
49
+ this.document = document
50
+ return true
51
+ } else {
52
+ return false
53
+ }
54
+ } catch (err) {
55
+ return false
56
+ }
57
+ }
58
+
59
+ getUrl = (): URL => {
60
+ const scheme = this.document.schemes?.includes("https") ? "https" : "http"
61
+ const basePath = this.document.basePath || ""
62
+ const host = this.document.host || "<host>"
63
+ return new URL(`${scheme}://${host}${basePath}`)
64
+ }
65
+
66
+ getInfo = async (): Promise<ImportInfo> => {
67
+ const name = this.document.info.title || "Swagger Import"
68
+ return {
69
+ name,
70
+ }
71
+ }
72
+
73
+ getQueries = async (datasourceId: string): Promise<Query[]> => {
74
+ const url = this.getUrl()
75
+ const queries = []
76
+
77
+ for (let [path, pathItem] of Object.entries(this.document.paths)) {
78
+ // parameters that apply to every operation in the path
79
+ let pathParams: OpenAPIV2.Parameter[] = []
80
+
81
+ for (let [key, opOrParams] of Object.entries(pathItem)) {
82
+ if (isParameter(key, opOrParams)) {
83
+ const pathParameters = opOrParams as OpenAPIV2.Parameter[]
84
+ pathParams.push(...pathParameters)
85
+ continue
86
+ }
87
+ // can not be a parameter, must be an operation
88
+ const operation = opOrParams as OpenAPIV2.OperationObject
89
+
90
+ const methodName = key
91
+ const name = operation.operationId || path
92
+ let queryString = ""
93
+ const headers: any = {}
94
+ let requestBody = undefined
95
+ const parameters: QueryParameter[] = []
96
+
97
+ if (operation.consumes) {
98
+ headers["Content-Type"] = operation.consumes[0]
99
+ }
100
+
101
+ // combine the path parameters with the operation parameters
102
+ const operationParams = operation.parameters || []
103
+ const allParams = [...pathParams, ...operationParams]
104
+
105
+ for (let param of allParams) {
106
+ if (parameterNotRef(param)) {
107
+ switch (param.in) {
108
+ case "query":
109
+ let prefix = ""
110
+ if (queryString) {
111
+ prefix = "&"
112
+ }
113
+ queryString = `${queryString}${prefix}${param.name}={{${param.name}}}`
114
+ break
115
+ case "header":
116
+ headers[param.name] = `{{${param.name}}}`
117
+ break
118
+ case "path":
119
+ // do nothing: param is already in the path
120
+ break
121
+ case "formData":
122
+ // future enhancement
123
+ break
124
+ case "body":
125
+ // set the request body to the example provided
126
+ // future enhancement: generate an example from the schema
127
+ let bodyParam: OpenAPIV2.InBodyParameterObject =
128
+ param as OpenAPIV2.InBodyParameterObject
129
+ if (param.schema.example) {
130
+ const schema = bodyParam.schema as OpenAPIV2.SchemaObject
131
+ requestBody = schema.example
132
+ }
133
+ break
134
+ }
135
+
136
+ // add the parameter if it can be bound in our config
137
+ if (["query", "header", "path"].includes(param.in)) {
138
+ parameters.push({
139
+ name: param.name,
140
+ default: param.default || "",
141
+ })
142
+ }
143
+ }
144
+ }
145
+
146
+ const query = this.constructQuery(
147
+ datasourceId,
148
+ name,
149
+ methodName,
150
+ path,
151
+ url,
152
+ queryString,
153
+ headers,
154
+ parameters,
155
+ requestBody
156
+ )
157
+ queries.push(query)
158
+ }
159
+ }
160
+
161
+ return queries
162
+ }
163
+ }