@budibase/server 0.9.185-alpha.0 → 0.9.185-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 (257) hide show
  1. package/Dockerfile +1 -1
  2. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  3. package/builder/assets/index.4a7c5636.css +1 -0
  4. package/builder/assets/index.708945dd.js +1316 -0
  5. package/builder/assets/vendor.470042a4.js +152 -0
  6. package/builder/assets/vendor.5e1fe644.css +1 -0
  7. package/builder/index.html +4 -4
  8. package/coverage/clover.xml +1060 -928
  9. package/coverage/coverage-final.json +90 -88
  10. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  11. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  12. package/coverage/lcov-report/api/controllers/application.js.html +43 -13
  13. package/coverage/lcov-report/api/controllers/auth.js.html +7 -7
  14. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  15. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  18. package/coverage/lcov-report/api/controllers/datasource.js.html +31 -7
  19. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  20. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  21. package/coverage/lcov-report/api/controllers/index.html +75 -75
  22. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  24. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  25. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  26. package/coverage/lcov-report/api/controllers/query.js.html +48 -210
  27. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  28. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/row/external.js.html +12 -6
  30. package/coverage/lcov-report/api/controllers/row/index.html +18 -18
  31. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  32. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  33. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +2 -2
  35. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  37. package/coverage/lcov-report/api/controllers/table/external.js.html +65 -8
  38. package/coverage/lcov-report/api/controllers/table/index.html +42 -42
  39. package/coverage/lcov-report/api/controllers/table/index.js.html +66 -12
  40. package/coverage/lcov-report/api/controllers/table/internal.js.html +49 -10
  41. package/coverage/lcov-report/api/controllers/table/utils.js.html +57 -45
  42. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  43. package/coverage/lcov-report/api/controllers/user.js.html +33 -18
  44. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/index.html +9 -9
  46. package/coverage/lcov-report/api/controllers/view/index.js.html +5 -5
  47. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  48. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  49. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  50. package/coverage/lcov-report/api/index.html +1 -1
  51. package/coverage/lcov-report/api/index.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  63. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +4 -4
  65. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  71. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  77. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  78. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  82. package/coverage/lcov-report/automations/actions.js.html +2 -2
  83. package/coverage/lcov-report/automations/automationUtils.js.html +3 -3
  84. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  85. package/coverage/lcov-report/automations/index.html +33 -48
  86. package/coverage/lcov-report/automations/index.js.html +2 -2
  87. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  92. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  94. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/index.html +14 -14
  96. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  99. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  104. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  106. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  109. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  114. package/coverage/lcov-report/automations/utils.js.html +42 -12
  115. package/coverage/lcov-report/constants/index.html +1 -1
  116. package/coverage/lcov-report/constants/index.js.html +5 -2
  117. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  118. package/coverage/lcov-report/constants/screens.js.html +1 -1
  119. package/coverage/lcov-report/db/client.js.html +2 -2
  120. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  121. package/coverage/lcov-report/db/index.html +2 -2
  122. package/coverage/lcov-report/db/index.js.html +1 -1
  123. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  124. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  125. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  126. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  127. package/coverage/lcov-report/db/newid.js.html +1 -1
  128. package/coverage/lcov-report/db/utils.js.html +1 -1
  129. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  130. package/coverage/lcov-report/events/index.html +6 -6
  131. package/coverage/lcov-report/events/index.js.html +1 -1
  132. package/coverage/lcov-report/events/utils.js.html +5 -5
  133. package/coverage/lcov-report/index.html +94 -79
  134. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  135. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  136. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  137. package/coverage/lcov-report/middleware/authorized.js.html +5 -5
  138. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  139. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  140. package/coverage/lcov-report/middleware/index.html +21 -21
  141. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  142. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  143. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  144. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  145. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  146. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +83 -32
  147. package/coverage/lcov-report/threads/index.html +141 -0
  148. package/coverage/lcov-report/threads/index.js.html +260 -0
  149. package/coverage/lcov-report/threads/query.js.html +269 -0
  150. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  151. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  152. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  153. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  154. package/coverage/lcov-report/utilities/global.js.html +2 -2
  155. package/coverage/lcov-report/utilities/index.html +34 -34
  156. package/coverage/lcov-report/utilities/index.js.html +12 -9
  157. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  158. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  159. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  160. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  161. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  162. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  163. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  164. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  165. package/coverage/lcov-report/utilities/security.js.html +3 -3
  166. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  167. package/coverage/lcov-report/utilities/users.js.html +1 -1
  168. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  169. package/coverage/lcov.info +1753 -1527
  170. package/dist/api/controllers/application.js +11 -1
  171. package/dist/api/controllers/datasource.js +6 -2
  172. package/dist/api/controllers/deploy/index.js +2 -0
  173. package/dist/api/controllers/dev.js +4 -1
  174. package/dist/api/controllers/query.js +27 -57
  175. package/dist/api/controllers/row/ExternalRequest.js +2 -2
  176. package/dist/api/controllers/row/external.js +1 -0
  177. package/dist/api/controllers/table/external.js +17 -0
  178. package/dist/api/controllers/table/index.js +21 -2
  179. package/dist/api/controllers/table/internal.js +10 -1
  180. package/dist/api/controllers/table/utils.js +28 -27
  181. package/dist/api/controllers/user.js +10 -6
  182. package/dist/api/routes/query.js +1 -1
  183. package/dist/api/routes/table.js +7 -1
  184. package/dist/app.js +2 -11
  185. package/dist/automations/bullboard.js +37 -10
  186. package/dist/automations/triggers.js +7 -3
  187. package/dist/automations/utils.js +11 -2
  188. package/dist/constants/index.js +1 -0
  189. package/dist/definitions/datasource.js +1 -0
  190. package/dist/integrations/base/IntegrationBase.js +2 -0
  191. package/dist/integrations/base/sql.js +48 -8
  192. package/dist/integrations/base/sqlTable.js +1 -2
  193. package/dist/integrations/mysql.js +3 -1
  194. package/dist/integrations/postgres.js +2 -2
  195. package/dist/middleware/builder.js +4 -1
  196. package/dist/package.json +7 -6
  197. package/dist/{automations/thread.js → threads/automation.js} +23 -7
  198. package/dist/threads/index.js +58 -0
  199. package/dist/threads/query.js +61 -0
  200. package/dist/tsconfig.tsbuildinfo +1 -1
  201. package/dist/utilities/csvParser.js +46 -5
  202. package/dist/utilities/index.js +1 -0
  203. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  204. package/dist/utilities/scriptRunner.js +4 -1
  205. package/package.json +8 -7
  206. package/scripts/likeCypress.ts +33 -0
  207. package/src/api/controllers/application.js +11 -1
  208. package/src/api/controllers/datasource.js +10 -2
  209. package/src/api/controllers/deploy/index.js +2 -0
  210. package/src/api/controllers/dev.js +4 -1
  211. package/src/api/controllers/query.js +26 -80
  212. package/src/api/controllers/row/ExternalRequest.ts +6 -2
  213. package/src/api/controllers/row/external.js +2 -0
  214. package/src/api/controllers/table/external.js +19 -0
  215. package/src/api/controllers/table/index.js +20 -2
  216. package/src/api/controllers/table/internal.js +14 -1
  217. package/src/api/controllers/table/utils.js +36 -32
  218. package/src/api/controllers/user.js +15 -10
  219. package/src/api/routes/query.js +1 -0
  220. package/src/api/routes/table.js +11 -0
  221. package/src/api/routes/tests/misc.spec.js +5 -1
  222. package/src/app.ts +2 -10
  223. package/src/automations/bullboard.js +28 -11
  224. package/src/automations/tests/automation.spec.js +3 -4
  225. package/src/automations/triggers.js +7 -3
  226. package/src/automations/utils.js +12 -2
  227. package/src/constants/index.js +1 -0
  228. package/src/definitions/datasource.ts +3 -2
  229. package/src/integrations/airtable.ts +2 -1
  230. package/src/integrations/arangodb.ts +2 -1
  231. package/src/integrations/base/IntegrationBase.ts +6 -0
  232. package/src/integrations/base/datasourcePlus.ts +2 -1
  233. package/src/integrations/base/sql.ts +51 -9
  234. package/src/integrations/base/sqlTable.ts +1 -4
  235. package/src/integrations/couchdb.ts +2 -1
  236. package/src/integrations/dynamodb.ts +2 -1
  237. package/src/integrations/elasticsearch.ts +2 -1
  238. package/src/integrations/mongodb.ts +2 -1
  239. package/src/integrations/mysql.ts +1 -1
  240. package/src/integrations/postgres.ts +5 -5
  241. package/src/integrations/rest.ts +2 -1
  242. package/src/integrations/s3.ts +2 -1
  243. package/src/middleware/builder.js +4 -1
  244. package/src/{automations/thread.js → threads/automation.js} +24 -7
  245. package/src/threads/index.js +60 -0
  246. package/src/threads/query.js +63 -0
  247. package/src/utilities/csvParser.js +48 -5
  248. package/src/utilities/index.js +1 -0
  249. package/src/utilities/queue/inMemoryQueue.js +7 -0
  250. package/src/utilities/scriptRunner.js +4 -1
  251. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  252. package/src/utilities/tests/csvParser.spec.js +3 -0
  253. package/tsconfig.json +1 -1
  254. package/builder/assets/index.0e6a5c20.js +0 -201
  255. package/builder/assets/index.cf21e4d2.css +0 -29
  256. package/builder/assets/vendor.278a305c.js +0 -9
  257. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -56,7 +56,7 @@ function parse(csvString, parsers) {
56
56
  });
57
57
  result.subscribe(row => {
58
58
  // For each CSV row parse all the columns that need parsed
59
- for (let key in parsers) {
59
+ for (let key of Object.keys(parsers)) {
60
60
  if (!schema[key] || schema[key].success) {
61
61
  // get the validator for the column type
62
62
  const validator = VALIDATORS[parsers[key].type];
@@ -79,15 +79,55 @@ function parse(csvString, parsers) {
79
79
  });
80
80
  });
81
81
  }
82
- function transform({ schema, csvString }) {
82
+ function updateSchema({ schema, existingTable }) {
83
+ if (!schema) {
84
+ return schema;
85
+ }
86
+ const finalSchema = {};
87
+ const schemaKeyMap = {};
88
+ Object.keys(schema).forEach(key => (schemaKeyMap[key.toLowerCase()] = key));
89
+ for (let [key, field] of Object.entries(existingTable.schema)) {
90
+ const lcKey = key.toLowerCase();
91
+ const foundKey = schemaKeyMap[lcKey];
92
+ if (foundKey) {
93
+ finalSchema[key] = schema[foundKey];
94
+ finalSchema[key].type = field.type;
95
+ }
96
+ }
97
+ return finalSchema;
98
+ }
99
+ function transform({ schema, csvString, existingTable }) {
83
100
  return __awaiter(this, void 0, void 0, function* () {
84
101
  const colParser = {};
85
- for (let key in schema) {
102
+ // make sure the table has all the columns required for import
103
+ if (existingTable) {
104
+ schema = updateSchema({ schema, existingTable });
105
+ }
106
+ for (let key of Object.keys(schema)) {
86
107
  colParser[key] = PARSERS[schema[key].type] || schema[key].type;
87
108
  }
88
109
  try {
89
- const json = yield csv({ colParser }).fromString(csvString);
90
- return json;
110
+ const data = yield csv({ colParser }).fromString(csvString);
111
+ const schemaKeyMap = {};
112
+ Object.keys(schema).forEach(key => (schemaKeyMap[key.toLowerCase()] = key));
113
+ for (let element of data) {
114
+ if (!data) {
115
+ continue;
116
+ }
117
+ for (let key of Object.keys(element)) {
118
+ const mappedKey = schemaKeyMap[key.toLowerCase()];
119
+ // isn't a column in the table, remove it
120
+ if (mappedKey == null) {
121
+ delete element[key];
122
+ }
123
+ // casing is different, fix it in row
124
+ else if (key !== mappedKey) {
125
+ element[mappedKey] = element[key];
126
+ delete element[key];
127
+ }
128
+ }
129
+ }
130
+ return data;
91
131
  }
92
132
  catch (err) {
93
133
  console.error(`Error transforming CSV to JSON for data import`, err);
@@ -98,4 +138,5 @@ function transform({ schema, csvString }) {
98
138
  module.exports = {
99
139
  parse,
100
140
  transform,
141
+ updateSchema,
101
142
  };
@@ -52,6 +52,7 @@ exports.objectStoreUrl = () => {
52
52
  * via a specific endpoint (under /api/assets/client).
53
53
  * @param {string} appId In production we need the appId to look up the correct bucket, as the
54
54
  * version of the client lib may differ between apps.
55
+ * @param {string} version The version to retrieve.
55
56
  * @return {string} The URL to be inserted into appPackage response or server rendered
56
57
  * app index file.
57
58
  */
@@ -93,5 +93,13 @@ class InMemoryQueue {
93
93
  getRepeatableJobs() {
94
94
  return [];
95
95
  }
96
+ /**
97
+ * Implemented for tests
98
+ */
99
+ clean() {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ return [];
102
+ });
103
+ }
96
104
  }
97
105
  module.exports = InMemoryQueue;
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  const fetch = require("node-fetch");
3
3
  const { VM, VMScript } = require("vm2");
4
+ const JS_TIMEOUT_MS = 1000;
4
5
  class ScriptRunner {
5
6
  constructor(script, context) {
6
7
  const code = `let fn = () => {\n${script}\n}; results.out = fn();`;
7
- this.vm = new VM();
8
+ this.vm = new VM({
9
+ timeout: JS_TIMEOUT_MS,
10
+ });
8
11
  this.results = { out: "" };
9
12
  this.vm.setGlobals(context);
10
13
  this.vm.setGlobal("fetch", fetch);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "0.9.185-alpha.0",
4
+ "version": "0.9.185-alpha.12",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -68,9 +68,11 @@
68
68
  "author": "Budibase",
69
69
  "license": "AGPL-3.0-or-later",
70
70
  "dependencies": {
71
- "@budibase/auth": "^0.9.185-alpha.0",
72
- "@budibase/client": "^0.9.185-alpha.0",
73
- "@budibase/string-templates": "^0.9.185-alpha.0",
71
+ "@budibase/auth": "^0.9.185-alpha.12",
72
+ "@budibase/client": "^0.9.185-alpha.12",
73
+ "@budibase/string-templates": "^0.9.185-alpha.12",
74
+ "@bull-board/api": "^3.7.0",
75
+ "@bull-board/koa": "^3.7.0",
74
76
  "@elastic/elasticsearch": "7.10.0",
75
77
  "@koa/router": "8.0.0",
76
78
  "@sendgrid/mail": "7.1.1",
@@ -80,7 +82,6 @@
80
82
  "aws-sdk": "^2.767.0",
81
83
  "bcryptjs": "2.4.3",
82
84
  "bull": "^3.22.4",
83
- "bull-board": "^2.0.1",
84
85
  "chmodr": "1.2.0",
85
86
  "csvtojson": "2.0.10",
86
87
  "dotenv": "8.2.0",
@@ -120,6 +121,7 @@
120
121
  "uuid": "3.3.2",
121
122
  "validate.js": "0.13.1",
122
123
  "vm2": "^3.9.3",
124
+ "worker-farm": "^1.7.0",
123
125
  "yargs": "13.2.4",
124
126
  "zlib": "1.0.5"
125
127
  },
@@ -138,7 +140,6 @@
138
140
  "copyfiles": "^2.4.1",
139
141
  "docker-compose": "^0.23.6",
140
142
  "eslint": "^6.8.0",
141
- "express": "^4.17.1",
142
143
  "jest": "^27.0.5",
143
144
  "nodemon": "^2.0.4",
144
145
  "prettier": "^2.3.1",
@@ -149,5 +150,5 @@
149
150
  "typescript": "^4.3.5",
150
151
  "update-dotenv": "^1.1.1"
151
152
  },
152
- "gitHead": "04cfca8b8ede8802307809b10e1215a5d87f22ad"
153
+ "gitHead": "c48ead6f4930f1dcaa2e6efc974bb38406e31e6d"
153
154
  }
@@ -0,0 +1,33 @@
1
+ /******************************************************
2
+ * This script just makes it easy to re-create *
3
+ * a cypress like environment for testing the backend *
4
+ ******************************************************/
5
+ const path = require("path")
6
+ const tmpdir = path.join(require("os").tmpdir(), ".budibase")
7
+
8
+ const MAIN_PORT = "10001"
9
+ const WORKER_PORT = "10002"
10
+
11
+ // @ts-ignore
12
+ process.env.PORT = MAIN_PORT
13
+ process.env.BUDIBASE_API_KEY = "6BE826CB-6B30-4AEC-8777-2E90464633DE"
14
+ process.env.NODE_ENV = "cypress"
15
+ process.env.ENABLE_ANALYTICS = "false"
16
+ process.env.JWT_SECRET = "budibase"
17
+ process.env.COUCH_URL = `leveldb://${tmpdir}/.data/`
18
+ process.env.SELF_HOSTED = "1"
19
+ process.env.WORKER_URL = `http://localhost:${WORKER_PORT}/`
20
+ process.env.MINIO_URL = `http://localhost:${MAIN_PORT}/`
21
+ process.env.MINIO_ACCESS_KEY = "budibase"
22
+ process.env.MINIO_SECRET_KEY = "budibase"
23
+ process.env.COUCH_DB_USER = "budibase"
24
+ process.env.COUCH_DB_PASSWORD = "budibase"
25
+ process.env.INTERNAL_API_KEY = "budibase"
26
+ process.env.ALLOW_DEV_AUTOMATIONS = "1"
27
+
28
+ // don't make this a variable or top level require
29
+ // it will cause environment module to be loaded prematurely
30
+ const server = require("../src/app")
31
+ process.env.PORT = WORKER_PORT
32
+ const worker = require("../../worker/src/index")
33
+ process.env.PORT = MAIN_PORT
@@ -45,6 +45,8 @@ const {
45
45
  } = require("../../utilities/fileSystem/clientLibrary")
46
46
  const { getTenantId, isMultiTenant } = require("@budibase/auth/tenancy")
47
47
  const { syncGlobalUsers } = require("./user")
48
+ const { app: appCache } = require("@budibase/auth/cache")
49
+ const { cleanupAutomations } = require("../../automations/utils")
48
50
 
49
51
  const URL_REGEX_SLASH = /\/|\\/g
50
52
 
@@ -254,6 +256,7 @@ exports.create = async ctx => {
254
256
  await createApp(appId)
255
257
  }
256
258
 
259
+ await appCache.invalidateAppMetadata(appId, newApplication)
257
260
  ctx.status = 200
258
261
  ctx.body = newApplication
259
262
  }
@@ -317,8 +320,12 @@ exports.delete = async ctx => {
317
320
  if (!env.isTest() && !ctx.query.unpublish) {
318
321
  await deleteApp(ctx.params.appId)
319
322
  }
323
+ if (ctx.query && ctx.query.unpublish) {
324
+ await cleanupAutomations(ctx.params.appId)
325
+ }
320
326
  // make sure the app/role doesn't stick around after the app has been deleted
321
327
  await removeAppFromUserRoles(ctx, ctx.params.appId)
328
+ await appCache.invalidateAppMetadata(ctx.params.appId)
322
329
 
323
330
  ctx.status = 200
324
331
  ctx.body = result
@@ -387,7 +394,10 @@ const updateAppPackage = async (ctx, appPackage, appId) => {
387
394
  // Redis, shouldn't ever store it
388
395
  delete newAppPackage.lockedBy
389
396
 
390
- return await db.put(newAppPackage)
397
+ const response = await db.put(newAppPackage)
398
+ // remove any cached metadata, so that it will be updated
399
+ await appCache.invalidateAppMetadata(appId)
400
+ return response
391
401
  }
392
402
 
393
403
  const createEmptyAppPackage = async (ctx, app) => {
@@ -119,8 +119,16 @@ exports.destroy = async function (ctx) {
119
119
  const db = new CouchDB(ctx.appId)
120
120
 
121
121
  // Delete all queries for the datasource
122
- const rows = await db.allDocs(getQueryParams(ctx.params.datasourceId, null))
123
- await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
122
+ const queries = await db.allDocs(
123
+ getQueryParams(ctx.params.datasourceId, null)
124
+ )
125
+ await db.bulkDocs(
126
+ queries.rows.map(row => ({
127
+ _id: row.id,
128
+ _rev: row.value.rev,
129
+ _deleted: true,
130
+ }))
131
+ )
124
132
 
125
133
  // delete the datasource
126
134
  await db.remove(ctx.params.datasourceId, ctx.params.revId)
@@ -6,6 +6,7 @@ const {
6
6
  disableAllCrons,
7
7
  enableCronTrigger,
8
8
  } = require("../../../automations/utils")
9
+ const { app: appCache } = require("@budibase/auth/cache")
9
10
 
10
11
  // the max time we can wait for an invalidation to complete before considering it failed
11
12
  const MAX_PENDING_TIME_MS = 30 * 60000
@@ -103,6 +104,7 @@ async function deployApp(deployment) {
103
104
  appDoc.appId = productionAppId
104
105
  appDoc.instance._id = productionAppId
105
106
  await db.put(appDoc)
107
+ await appCache.invalidateAppMetadata(productionAppId)
106
108
  console.log("New app doc written successfully.")
107
109
  await initDeployedApp(productionAppId)
108
110
  console.log("Deployed app initialised, setting deployment to successful")
@@ -6,6 +6,7 @@ const { request } = require("../../utilities/workerRequests")
6
6
  const { clearLock } = require("../../utilities/redis")
7
7
  const { Replication } = require("@budibase/auth").db
8
8
  const { DocumentTypes } = require("../../db/utils")
9
+ const { app: appCache } = require("@budibase/auth/cache")
9
10
 
10
11
  async function redirect(ctx, method, path = "global") {
11
12
  const { devPath } = ctx.params
@@ -24,7 +25,8 @@ async function redirect(ctx, method, path = "global") {
24
25
  )
25
26
  )
26
27
  if (response.status !== 200) {
27
- ctx.throw(response.status, response.statusText)
28
+ const err = await response.text()
29
+ ctx.throw(400, err)
28
30
  }
29
31
  const cookie = response.headers.get("set-cookie")
30
32
  if (cookie) {
@@ -106,6 +108,7 @@ exports.revert = async ctx => {
106
108
  appDoc.appId = appId
107
109
  appDoc.instance._id = appId
108
110
  await db.put(appDoc)
111
+ await appCache.invalidateAppMetadata(appId)
109
112
  ctx.body = {
110
113
  message: "Reverted changes successfully.",
111
114
  }
@@ -1,10 +1,11 @@
1
1
  const { processString } = require("@budibase/string-templates")
2
2
  const CouchDB = require("../../db")
3
3
  const { generateQueryID, getQueryParams } = require("../../db/utils")
4
- const { integrations } = require("../../integrations")
5
4
  const { BaseQueryVerbs } = require("../../constants")
6
5
  const env = require("../../environment")
7
- const ScriptRunner = require("../../utilities/scriptRunner")
6
+ const { Thread, ThreadType } = require("../../threads")
7
+
8
+ const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
8
9
 
9
10
  // simple function to append "readable" to all read queries
10
11
  function enrichQueries(input) {
@@ -18,47 +19,6 @@ function enrichQueries(input) {
18
19
  return wasArray ? queries : queries[0]
19
20
  }
20
21
 
21
- function formatResponse(resp) {
22
- if (typeof resp === "string") {
23
- try {
24
- resp = JSON.parse(resp)
25
- } catch (err) {
26
- resp = { response: resp }
27
- }
28
- }
29
- return resp
30
- }
31
-
32
- async function runAndTransform(
33
- integration,
34
- queryVerb,
35
- enrichedQuery,
36
- transformer
37
- ) {
38
- let rows = formatResponse(await integration[queryVerb](enrichedQuery))
39
-
40
- // transform as required
41
- if (transformer) {
42
- const runner = new ScriptRunner(transformer, { data: rows })
43
- rows = runner.execute()
44
- }
45
-
46
- // needs to an array for next step
47
- if (!Array.isArray(rows)) {
48
- rows = [rows]
49
- }
50
-
51
- // map into JSON if just raw primitive here
52
- if (rows.find(row => typeof row !== "object")) {
53
- rows = rows.map(value => ({ value }))
54
- }
55
-
56
- // get all the potential fields in the schema
57
- let keys = rows.flatMap(Object.keys)
58
-
59
- return { rows, keys }
60
- }
61
-
62
22
  exports.fetch = async function (ctx) {
63
23
  const db = new CouchDB(ctx.appId)
64
24
 
@@ -143,30 +103,23 @@ exports.preview = async function (ctx) {
143
103
 
144
104
  const datasource = await db.get(ctx.request.body.datasourceId)
145
105
 
146
- const Integration = integrations[datasource.source]
147
-
148
- if (!Integration) {
149
- ctx.throw(400, "Integration type does not exist.")
150
- }
151
-
152
106
  const { fields, parameters, queryVerb, transformer } = ctx.request.body
153
107
  const enrichedQuery = await enrichQueryFields(fields, parameters)
154
- const integration = new Integration(datasource.config)
155
108
 
156
- const { rows, keys } = await runAndTransform(
157
- integration,
158
- queryVerb,
159
- enrichedQuery,
160
- transformer
161
- )
109
+ try {
110
+ const { rows, keys } = await Runner.run({
111
+ datasource,
112
+ queryVerb,
113
+ query: enrichedQuery,
114
+ transformer,
115
+ })
162
116
 
163
- ctx.body = {
164
- rows,
165
- schemaFields: [...new Set(keys)],
166
- }
167
- // cleanup
168
- if (integration.end) {
169
- integration.end()
117
+ ctx.body = {
118
+ rows,
119
+ schemaFields: [...new Set(keys)],
120
+ }
121
+ } catch (err) {
122
+ ctx.throw(400, err)
170
123
  }
171
124
  }
172
125
 
@@ -176,29 +129,22 @@ exports.execute = async function (ctx) {
176
129
  const query = await db.get(ctx.params.queryId)
177
130
  const datasource = await db.get(query.datasourceId)
178
131
 
179
- const Integration = integrations[datasource.source]
180
-
181
- if (!Integration) {
182
- ctx.throw(400, "Integration type does not exist.")
183
- }
184
-
185
132
  const enrichedQuery = await enrichQueryFields(
186
133
  query.fields,
187
134
  ctx.request.body.parameters
188
135
  )
189
- const integration = new Integration(datasource.config)
190
136
 
191
137
  // call the relevant CRUD method on the integration class
192
- const { rows } = await runAndTransform(
193
- integration,
194
- query.queryVerb,
195
- enrichedQuery,
196
- query.transformer
197
- )
198
- ctx.body = rows
199
- // cleanup
200
- if (integration.end) {
201
- integration.end()
138
+ try {
139
+ const { rows } = await Runner.run({
140
+ datasource,
141
+ queryVerb: query.queryVerb,
142
+ query: enrichedQuery,
143
+ transformer: query.transformer,
144
+ })
145
+ ctx.body = rows
146
+ } catch (err) {
147
+ ctx.throw(400, err)
202
148
  }
203
149
  }
204
150
 
@@ -33,6 +33,7 @@ interface RunConfig {
33
33
  sort?: SortJson
34
34
  paginate?: PaginationJson
35
35
  row?: Row
36
+ rows?: Row[]
36
37
  }
37
38
 
38
39
  module External {
@@ -600,7 +601,10 @@ module External {
600
601
  throw `Unable to process query, table "${tableName}" not defined.`
601
602
  }
602
603
  // look for specific components of config which may not be considered acceptable
603
- let { id, row, filters, sort, paginate } = cleanupConfig(config, table)
604
+ let { id, row, filters, sort, paginate, rows } = cleanupConfig(
605
+ config,
606
+ table
607
+ )
604
608
  filters = buildFilters(id, filters || {}, table)
605
609
  const relationships = this.buildRelationships(table)
606
610
  // clean up row on ingress using schema
@@ -626,7 +630,7 @@ module External {
626
630
  sort,
627
631
  paginate,
628
632
  relationships,
629
- body: row,
633
+ body: row || rows,
630
634
  // pass an id filter into extra, purely for mysql/returning
631
635
  extra: {
632
636
  idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
@@ -30,6 +30,8 @@ async function handleRequest(appId, operation, tableId, opts = {}) {
30
30
  )
31
31
  }
32
32
 
33
+ exports.handleRequest = handleRequest
34
+
33
35
  exports.patch = async ctx => {
34
36
  const appId = ctx.appId
35
37
  const inputs = ctx.request.body
@@ -17,6 +17,8 @@ const {
17
17
  } = require("../../../constants")
18
18
  const { makeExternalQuery } = require("../../../integrations/base/utils")
19
19
  const { cloneDeep } = require("lodash/fp")
20
+ const csvParser = require("../../../utilities/csvParser")
21
+ const { handleRequest } = require("../row/external")
20
22
 
21
23
  async function makeTableRequest(
22
24
  datasource,
@@ -279,3 +281,20 @@ exports.destroy = async function (ctx) {
279
281
 
280
282
  return tableToDelete
281
283
  }
284
+
285
+ exports.bulkImport = async function (ctx) {
286
+ const appId = ctx.appId
287
+ const table = await getTable(appId, ctx.params.tableId)
288
+ const { dataImport } = ctx.request.body
289
+ if (!dataImport || !dataImport.schema || !dataImport.csvString) {
290
+ ctx.throw(400, "Provided data import information is invalid.")
291
+ }
292
+ const rows = await csvParser.transform({
293
+ ...dataImport,
294
+ existingTable: table,
295
+ })
296
+ await handleRequest(appId, DataSourceOperation.BULK_CREATE, table._id, {
297
+ rows,
298
+ })
299
+ return table
300
+ }
@@ -81,8 +81,26 @@ exports.destroy = async function (ctx) {
81
81
  ctx.body = { message: `Table ${tableId} deleted.` }
82
82
  }
83
83
 
84
+ exports.bulkImport = async function (ctx) {
85
+ const tableId = ctx.params.tableId
86
+ await pickApi({ tableId }).bulkImport(ctx)
87
+ // right now we don't trigger anything for bulk import because it
88
+ // can only be done in the builder, but in the future we may need to
89
+ // think about events for bulk items
90
+ ctx.status = 200
91
+ ctx.body = { message: `Bulk rows created.` }
92
+ }
93
+
84
94
  exports.validateCSVSchema = async function (ctx) {
85
- const { csvString, schema = {} } = ctx.request.body
86
- const result = await csvParser.parse(csvString, schema)
95
+ // tableId being specified means its an import to an existing table
96
+ const { csvString, schema = {}, tableId } = ctx.request.body
97
+ let existingTable
98
+ if (tableId) {
99
+ existingTable = await getTable(ctx.appId, tableId)
100
+ }
101
+ let result = await csvParser.parse(csvString, schema)
102
+ if (existingTable) {
103
+ result = csvParser.updateSchema({ schema: result, existingTable })
104
+ }
87
105
  ctx.body = { schema: result }
88
106
  }
@@ -2,7 +2,12 @@ const CouchDB = require("../../../db")
2
2
  const linkRows = require("../../../db/linkedRows")
3
3
  const { getRowParams, generateTableID } = require("../../../db/utils")
4
4
  const { FieldTypes } = require("../../../constants")
5
- const { TableSaveFunctions, hasTypeChanged } = require("./utils")
5
+ const {
6
+ TableSaveFunctions,
7
+ hasTypeChanged,
8
+ getTable,
9
+ handleDataImport,
10
+ } = require("./utils")
6
11
 
7
12
  exports.save = async function (ctx) {
8
13
  const appId = ctx.appId
@@ -140,3 +145,11 @@ exports.destroy = async function (ctx) {
140
145
 
141
146
  return tableToDelete
142
147
  }
148
+
149
+ exports.bulkImport = async function (ctx) {
150
+ const appId = ctx.appId
151
+ const table = await getTable(appId, ctx.params.tableId)
152
+ const { dataImport } = ctx.request.body
153
+ await handleDataImport(appId, ctx.user, table, dataImport)
154
+ return table
155
+ }
@@ -72,43 +72,47 @@ exports.makeSureTableUpToDate = (table, tableToSave) => {
72
72
  }
73
73
 
74
74
  exports.handleDataImport = async (appId, user, table, dataImport) => {
75
+ if (!dataImport || !dataImport.csvString) {
76
+ return table
77
+ }
75
78
  const db = new CouchDB(appId)
76
- if (dataImport && dataImport.csvString) {
77
- // Populate the table with rows imported from CSV in a bulk update
78
- const data = await csvParser.transform(dataImport)
79
-
80
- let finalData = []
81
- for (let i = 0; i < data.length; i++) {
82
- let row = data[i]
83
- row._id = generateRowID(table._id)
84
- row.tableId = table._id
85
- const processed = inputProcessing(user, table, row, {
86
- noAutoRelationships: true,
87
- })
88
- table = processed.table
89
- row = processed.row
90
-
91
- for (let [fieldName, schema] of Object.entries(table.schema)) {
92
- // check whether the options need to be updated for inclusion as part of the data import
93
- if (
94
- schema.type === FieldTypes.OPTIONS &&
95
- (!schema.constraints.inclusion ||
96
- schema.constraints.inclusion.indexOf(row[fieldName]) === -1)
97
- ) {
98
- schema.constraints.inclusion = [
99
- ...schema.constraints.inclusion,
100
- row[fieldName],
101
- ]
102
- }
79
+ // Populate the table with rows imported from CSV in a bulk update
80
+ const data = await csvParser.transform({
81
+ ...dataImport,
82
+ existingTable: table,
83
+ })
84
+
85
+ let finalData = []
86
+ for (let i = 0; i < data.length; i++) {
87
+ let row = data[i]
88
+ row._id = generateRowID(table._id)
89
+ row.tableId = table._id
90
+ const processed = inputProcessing(user, table, row, {
91
+ noAutoRelationships: true,
92
+ })
93
+ table = processed.table
94
+ row = processed.row
95
+
96
+ for (let [fieldName, schema] of Object.entries(table.schema)) {
97
+ // check whether the options need to be updated for inclusion as part of the data import
98
+ if (
99
+ schema.type === FieldTypes.OPTIONS &&
100
+ (!schema.constraints.inclusion ||
101
+ schema.constraints.inclusion.indexOf(row[fieldName]) === -1)
102
+ ) {
103
+ schema.constraints.inclusion = [
104
+ ...schema.constraints.inclusion,
105
+ row[fieldName],
106
+ ]
103
107
  }
104
-
105
- finalData.push(row)
106
108
  }
107
109
 
108
- await db.bulkDocs(finalData)
109
- let response = await db.put(table)
110
- table._rev = response._rev
110
+ finalData.push(row)
111
111
  }
112
+
113
+ await db.bulkDocs(finalData)
114
+ let response = await db.put(table)
115
+ table._rev = response._rev
112
116
  return table
113
117
  }
114
118