@budibase/server 0.9.172 → 0.9.173-alpha.3

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 (261) hide show
  1. package/__mocks__/{mysql.ts → mysql2.ts} +0 -0
  2. package/builder/assets/{index.dbc6728e.css → index.7469e1e4.css} +2 -2
  3. package/builder/assets/{index.9ab01cd4.js → index.b38aa4d6.js} +34 -34
  4. package/builder/assets/{vendor.54435e8f.js → vendor.278a305c.js} +1 -1
  5. package/builder/index.html +3 -3
  6. package/coverage/clover.xml +973 -849
  7. package/coverage/coverage-final.json +47 -46
  8. package/coverage/lcov-report/api/controllers/analytics.js.html +21 -9
  9. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/application.js.html +186 -84
  11. package/coverage/lcov-report/api/controllers/auth.js.html +37 -10
  12. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/backup.js.html +6 -9
  14. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/dev.js.html +41 -17
  18. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/index.html +71 -71
  20. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/permission.js.html +7 -4
  24. package/coverage/lcov-report/api/controllers/query.js.html +129 -24
  25. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/index.html +5 -5
  29. package/coverage/lcov-report/api/controllers/row/index.js.html +15 -15
  30. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/screen.js.html +9 -9
  34. package/coverage/lcov-report/api/controllers/script.js.html +12 -57
  35. package/coverage/lcov-report/api/controllers/table/index.html +28 -28
  36. package/coverage/lcov-report/api/controllers/table/index.js.html +16 -37
  37. package/coverage/lcov-report/api/controllers/table/utils.js.html +279 -33
  38. package/coverage/lcov-report/api/controllers/templates.js.html +49 -13
  39. package/coverage/lcov-report/api/controllers/user.js.html +3 -3
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +19 -19
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +8 -8
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +54 -15
  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 +3 -3
  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 +5 -2
  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 +26 -11
  59. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/index.html +9 -9
  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 +9 -3
  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 +1 -1
  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 +1 -1
  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 +31 -10
  79. package/coverage/lcov-report/automations/automationUtils.js.html +14 -86
  80. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  81. package/coverage/lcov-report/automations/index.html +37 -37
  82. package/coverage/lcov-report/automations/index.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/bash.js.html +10 -7
  84. package/coverage/lcov-report/automations/steps/createRow.js.html +2 -2
  85. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/deleteRow.js.html +8 -5
  87. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/executeQuery.js.html +10 -7
  89. package/coverage/lcov-report/automations/steps/executeScript.js.html +10 -7
  90. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/index.html +57 -57
  92. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +10 -7
  94. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -7
  95. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +10 -7
  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 +14 -14
  99. package/coverage/lcov-report/automations/steps/utils.js.html +10 -10
  100. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  101. package/coverage/lcov-report/automations/thread.js.html +54 -12
  102. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  111. package/coverage/lcov-report/automations/utils.js.html +28 -28
  112. package/coverage/lcov-report/constants/index.html +1 -1
  113. package/coverage/lcov-report/constants/index.js.html +5 -2
  114. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  115. package/coverage/lcov-report/constants/screens.js.html +2 -2
  116. package/coverage/lcov-report/db/client.js.html +1 -1
  117. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  118. package/coverage/lcov-report/db/index.html +1 -1
  119. package/coverage/lcov-report/db/index.js.html +1 -1
  120. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +12 -12
  121. package/coverage/lcov-report/db/linkedRows/index.html +18 -18
  122. package/coverage/lcov-report/db/linkedRows/index.js.html +47 -26
  123. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  124. package/coverage/lcov-report/db/newid.js.html +2 -2
  125. package/coverage/lcov-report/db/utils.js.html +17 -17
  126. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  127. package/coverage/lcov-report/events/index.html +1 -1
  128. package/coverage/lcov-report/events/index.js.html +1 -1
  129. package/coverage/lcov-report/events/utils.js.html +1 -1
  130. package/coverage/lcov-report/index.html +107 -107
  131. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  132. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  133. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  134. package/coverage/lcov-report/middleware/authorized.js.html +2 -2
  135. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  136. package/coverage/lcov-report/middleware/currentapp.js.html +52 -25
  137. package/coverage/lcov-report/middleware/index.html +15 -15
  138. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  139. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  140. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  141. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  142. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  143. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  144. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  145. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  146. package/coverage/lcov-report/utilities/global.js.html +27 -27
  147. package/coverage/lcov-report/utilities/index.html +32 -17
  148. package/coverage/lcov-report/utilities/index.js.html +4 -4
  149. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +29 -8
  150. package/coverage/lcov-report/utilities/queue/index.html +15 -15
  151. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  152. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  153. package/coverage/lcov-report/utilities/rowProcessor/index.html +14 -14
  154. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +38 -8
  155. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  156. package/coverage/lcov-report/utilities/scriptRunner.js.html +143 -0
  157. package/coverage/lcov-report/utilities/security.js.html +1 -1
  158. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  159. package/coverage/lcov-report/utilities/users.js.html +1 -1
  160. package/coverage/lcov-report/utilities/workerRequests.js.html +19 -19
  161. package/coverage/lcov.info +1692 -1452
  162. package/dist/api/controllers/analytics.js +4 -0
  163. package/dist/api/controllers/application.js +185 -171
  164. package/dist/api/controllers/auth.js +12 -2
  165. package/dist/api/controllers/backup.js +4 -4
  166. package/dist/api/controllers/deploy/index.js +3 -16
  167. package/dist/api/controllers/dev.js +17 -11
  168. package/dist/api/controllers/permission.js +1 -0
  169. package/dist/api/controllers/query.js +26 -8
  170. package/dist/api/controllers/row/ExternalRequest.js +46 -5
  171. package/dist/api/controllers/script.js +4 -16
  172. package/dist/api/controllers/table/index.js +5 -10
  173. package/dist/api/controllers/table/utils.js +83 -10
  174. package/dist/api/controllers/templates.js +18 -3
  175. package/dist/api/controllers/view/viewBuilder.js +15 -1
  176. package/dist/api/routes/application.js +1 -0
  177. package/dist/api/routes/dev.js +8 -4
  178. package/dist/api/routes/query.js +3 -1
  179. package/dist/api/routes/tests/utilities/TestFunctions.js +7 -9
  180. package/dist/automations/actions.js +9 -3
  181. package/dist/automations/automationUtils.js +8 -29
  182. package/dist/automations/steps/bash.js +2 -1
  183. package/dist/automations/steps/createRow.js +1 -1
  184. package/dist/automations/steps/deleteRow.js +2 -1
  185. package/dist/automations/steps/executeQuery.js +2 -1
  186. package/dist/automations/steps/executeScript.js +2 -1
  187. package/dist/automations/steps/outgoingWebhook.js +2 -1
  188. package/dist/automations/steps/queryRows.js +2 -1
  189. package/dist/automations/steps/sendSmtpEmail.js +2 -1
  190. package/dist/automations/steps/updateRow.js +6 -2
  191. package/dist/automations/thread.js +14 -3
  192. package/dist/constants/index.js +1 -0
  193. package/dist/db/linkedRows/index.js +9 -6
  194. package/dist/integrations/base/sql.js +4 -4
  195. package/dist/integrations/mysql.js +1 -1
  196. package/dist/integrations/utils.js +17 -1
  197. package/dist/middleware/currentapp.js +8 -2
  198. package/dist/package.json +7 -6
  199. package/dist/tests/utilities/TestConfiguration.js +34 -19
  200. package/dist/tests/utilities/controllers.js +1 -0
  201. package/dist/tsconfig.tsbuildinfo +1 -1
  202. package/dist/utilities/fileSystem/index.js +49 -33
  203. package/dist/utilities/global.js +1 -1
  204. package/dist/utilities/queue/inMemoryQueue.js +6 -0
  205. package/dist/utilities/rowProcessor/index.js +8 -0
  206. package/dist/utilities/scriptRunner.js +19 -0
  207. package/package.json +8 -7
  208. package/scripts/jestSetup.js +2 -0
  209. package/src/api/controllers/analytics.js +4 -0
  210. package/src/api/controllers/application.js +43 -9
  211. package/src/api/controllers/auth.js +12 -3
  212. package/src/api/controllers/backup.js +4 -5
  213. package/src/api/controllers/deploy/index.js +3 -18
  214. package/src/api/controllers/dev.js +16 -8
  215. package/src/api/controllers/permission.js +1 -0
  216. package/src/api/controllers/query.js +46 -11
  217. package/src/api/controllers/row/ExternalRequest.ts +53 -4
  218. package/src/api/controllers/script.js +4 -19
  219. package/src/api/controllers/table/index.js +5 -12
  220. package/src/api/controllers/table/utils.js +94 -12
  221. package/src/api/controllers/templates.js +17 -5
  222. package/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap +1 -1
  223. package/src/api/controllers/view/viewBuilder.js +14 -1
  224. package/src/api/routes/application.js +1 -0
  225. package/src/api/routes/dev.js +9 -4
  226. package/src/api/routes/query.js +3 -1
  227. package/src/api/routes/tests/auth.spec.js +1 -2
  228. package/src/api/routes/tests/permissions.spec.js +3 -0
  229. package/src/api/routes/tests/query.spec.js +2 -2
  230. package/src/api/routes/tests/routing.spec.js +24 -8
  231. package/src/api/routes/tests/user.spec.js +1 -1
  232. package/src/api/routes/tests/utilities/TestFunctions.js +7 -9
  233. package/src/api/routes/tests/webhook.spec.js +4 -1
  234. package/src/automations/actions.js +10 -3
  235. package/src/automations/automationUtils.js +7 -31
  236. package/src/automations/steps/bash.js +2 -1
  237. package/src/automations/steps/createRow.js +1 -1
  238. package/src/automations/steps/deleteRow.js +2 -1
  239. package/src/automations/steps/executeQuery.js +2 -1
  240. package/src/automations/steps/executeScript.js +2 -1
  241. package/src/automations/steps/outgoingWebhook.js +2 -1
  242. package/src/automations/steps/queryRows.js +2 -1
  243. package/src/automations/steps/sendSmtpEmail.js +2 -1
  244. package/src/automations/steps/updateRow.js +6 -6
  245. package/src/automations/thread.js +17 -3
  246. package/src/constants/index.js +1 -0
  247. package/src/db/linkedRows/index.js +14 -7
  248. package/src/integrations/base/sql.ts +11 -3
  249. package/src/integrations/mysql.ts +1 -1
  250. package/src/integrations/tests/mongo.spec.js +10 -6
  251. package/src/integrations/tests/mysql.spec.js +1 -1
  252. package/src/integrations/utils.ts +18 -0
  253. package/src/middleware/currentapp.js +11 -2
  254. package/src/middleware/tests/currentapp.spec.js +3 -3
  255. package/src/tests/utilities/TestConfiguration.js +47 -19
  256. package/src/tests/utilities/controllers.js +1 -0
  257. package/src/utilities/fileSystem/index.js +65 -43
  258. package/src/utilities/global.js +1 -1
  259. package/src/utilities/queue/inMemoryQueue.js +7 -0
  260. package/src/utilities/rowProcessor/index.js +10 -0
  261. package/src/utilities/scriptRunner.js +21 -0
@@ -22,11 +22,10 @@ var __rest = (this && this.__rest) || function (s, e) {
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  const datasource_1 = require("../../../definitions/datasource");
24
24
  const utils_1 = require("../../../integrations/utils");
25
- const constants_1 = require("../../../constants");
26
25
  var External;
27
26
  (function (External) {
28
27
  const { makeExternalQuery } = require("./utils");
29
- const { DataSourceOperation, FieldTypes } = require("../../../constants");
28
+ const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
30
29
  const { breakExternalTableId, isSQL } = require("../../../integrations/utils");
31
30
  const { processObjectSync } = require("@budibase/string-templates");
32
31
  const { cloneDeep } = require("lodash/fp");
@@ -67,6 +66,46 @@ var External;
67
66
  equal,
68
67
  };
69
68
  }
69
+ /**
70
+ * This function checks the incoming parameters to make sure all the inputs are
71
+ * valid based on on the table schema. The main thing this is looking for is when a
72
+ * user has made use of the _id field of a row for a foreign key or a search parameter.
73
+ * In these cases the key will be sent up as [1], rather than 1. In these cases we will
74
+ * simplify it down to the requirements. This function is quite complex as we try to be
75
+ * relatively restrictive over what types of columns we will perform this action for.
76
+ */
77
+ function cleanupConfig(config, table) {
78
+ const primaryOptions = [
79
+ FieldTypes.STRING,
80
+ FieldTypes.LONGFORM,
81
+ FieldTypes.OPTIONS,
82
+ FieldTypes.NUMBER,
83
+ ];
84
+ // filter out fields which cannot be keys
85
+ const fieldNames = Object.entries(table.schema)
86
+ .filter(schema => primaryOptions.find(val => val === schema[1].type))
87
+ .map(([fieldName]) => fieldName);
88
+ const iterateObject = (obj) => {
89
+ for (let [field, value] of Object.entries(obj)) {
90
+ if (fieldNames.find(name => name === field) && utils_1.isRowId(value)) {
91
+ obj[field] = utils_1.convertRowId(value);
92
+ }
93
+ }
94
+ };
95
+ // check the row and filters to make sure they aren't a key of some sort
96
+ if (config.filters) {
97
+ for (let filter of Object.values(config.filters)) {
98
+ if (typeof filter !== "object" || Object.keys(filter).length === 0) {
99
+ continue;
100
+ }
101
+ iterateObject(filter);
102
+ }
103
+ }
104
+ if (config.row) {
105
+ iterateObject(config.row);
106
+ }
107
+ return config;
108
+ }
70
109
  function generateIdForRow(row, table) {
71
110
  const primary = table.primary;
72
111
  if (!row || !primary) {
@@ -316,7 +355,7 @@ var External;
316
355
  if (field.type !== FieldTypes.LINK || !field.fieldName) {
317
356
  continue;
318
357
  }
319
- const isMany = field.relationshipType === constants_1.RelationshipTypes.MANY_TO_MANY;
358
+ const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY;
320
359
  const tableId = isMany ? field.through : field.tableId;
321
360
  const manyKey = field.throughFrom || primaryKey;
322
361
  const fieldName = isMany ? manyKey : field.fieldName;
@@ -430,7 +469,7 @@ var External;
430
469
  }
431
470
  return fields;
432
471
  }
433
- run({ id, row, filters, sort, paginate }) {
472
+ run(config) {
434
473
  return __awaiter(this, void 0, void 0, function* () {
435
474
  const { appId, operation, tableId } = this;
436
475
  let { datasourceId, tableName } = breakExternalTableId(tableId);
@@ -447,9 +486,11 @@ var External;
447
486
  if (!table) {
448
487
  throw `Unable to process query, table "${tableName}" not defined.`;
449
488
  }
450
- // clean up row on ingress using schema
489
+ // look for specific components of config which may not be considered acceptable
490
+ let { id, row, filters, sort, paginate } = cleanupConfig(config, table);
451
491
  filters = buildFilters(id, filters || {}, table);
452
492
  const relationships = this.buildRelationships(table);
493
+ // clean up row on ingress using schema
453
494
  const processed = this.inputProcessing(row, table);
454
495
  row = processed.row;
455
496
  if (operation === DataSourceOperation.DELETE &&
@@ -8,24 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- const fetch = require("node-fetch");
12
- const vm = require("vm");
13
- class ScriptExecutor {
14
- constructor(body) {
15
- const code = `let fn = () => {\n${body.script}\n}; out = fn();`;
16
- this.script = new vm.Script(code);
17
- this.context = vm.createContext(body.context);
18
- this.context.fetch = fetch;
19
- }
20
- execute() {
21
- this.script.runInContext(this.context);
22
- return this.context.out;
23
- }
24
- }
11
+ const ScriptRunner = require("../../utilities/scriptRunner");
25
12
  exports.execute = function (ctx) {
26
13
  return __awaiter(this, void 0, void 0, function* () {
27
- const executor = new ScriptExecutor(ctx.request.body);
28
- ctx.body = executor.execute();
14
+ const { script, context } = ctx.request.body;
15
+ const runner = new ScriptRunner(script, context);
16
+ ctx.body = runner.execute();
29
17
  });
30
18
  };
31
19
  exports.save = function (ctx) {
@@ -24,8 +24,7 @@ const linkRows = require("../../../db/linkedRows");
24
24
  const csvParser = require("../../../utilities/csvParser");
25
25
  const { getRowParams, getTableParams, generateTableID, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils");
26
26
  const { FieldTypes } = require("../../../constants");
27
- const { TableSaveFunctions, getExternalTable } = require("./utils");
28
- const { isExternalTable, breakExternalTableId, } = require("../../../integrations/utils");
27
+ const { TableSaveFunctions, getTable } = require("./utils");
29
28
  exports.fetch = function (ctx) {
30
29
  return __awaiter(this, void 0, void 0, function* () {
31
30
  const db = new CouchDB(ctx.appId);
@@ -44,15 +43,8 @@ exports.fetch = function (ctx) {
44
43
  };
45
44
  exports.find = function (ctx) {
46
45
  return __awaiter(this, void 0, void 0, function* () {
47
- const db = new CouchDB(ctx.appId);
48
46
  const tableId = ctx.params.id;
49
- if (isExternalTable(tableId)) {
50
- let { datasourceId, tableName } = breakExternalTableId(tableId);
51
- ctx.body = yield getExternalTable(ctx.appId, datasourceId, tableName);
52
- }
53
- else {
54
- ctx.body = yield db.get(ctx.params.id);
55
- }
47
+ ctx.body = yield getTable(ctx.appId, tableId);
56
48
  });
57
49
  };
58
50
  exports.save = function (ctx) {
@@ -81,6 +73,9 @@ exports.save = function (ctx) {
81
73
  for (let propKey of Object.keys(tableToSave.schema)) {
82
74
  let column = tableToSave.schema[propKey];
83
75
  let oldColumn = oldTable.schema[propKey];
76
+ if (oldColumn && oldColumn.type === "internal") {
77
+ oldColumn.type = "auto";
78
+ }
84
79
  if (oldColumn && oldColumn.type !== column.type) {
85
80
  ctx.throw(400, "Cannot change the type of a column");
86
81
  }
@@ -9,13 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  const CouchDB = require("../../../db");
12
- const linkRows = require("../../../db/linkedRows");
13
12
  const csvParser = require("../../../utilities/csvParser");
14
13
  const { getRowParams, generateRowID, InternalTables, } = require("../../../db/utils");
15
14
  const { isEqual } = require("lodash/fp");
16
15
  const { AutoFieldSubTypes, FieldTypes } = require("../../../constants");
17
16
  const { inputProcessing } = require("../../../utilities/rowProcessor");
18
17
  const { USERS_TABLE_SCHEMA } = require("../../../constants");
18
+ const { isExternalTable, breakExternalTableId, } = require("../../../integrations/utils");
19
+ const { getViews, saveView } = require("../view/utils");
20
+ const viewTemplate = require("../view/viewBuilder");
19
21
  exports.checkForColumnUpdates = (db, oldTable, updatedTable) => __awaiter(void 0, void 0, void 0, function* () {
20
22
  let updatedRows = [];
21
23
  const rename = updatedTable._rename;
@@ -25,6 +27,7 @@ exports.checkForColumnUpdates = (db, oldTable, updatedTable) => __awaiter(void 0
25
27
  }
26
28
  // check for renaming of columns or deleted columns
27
29
  if (rename || deletedColumns.length !== 0) {
30
+ // Update all rows
28
31
  const rows = yield db.allDocs(getRowParams(updatedTable._id, null, {
29
32
  include_docs: true,
30
33
  }));
@@ -38,6 +41,8 @@ exports.checkForColumnUpdates = (db, oldTable, updatedTable) => __awaiter(void 0
38
41
  }
39
42
  return doc;
40
43
  });
44
+ // Update views
45
+ yield exports.checkForViewUpdates(db, updatedTable, rename, deletedColumns);
41
46
  delete updatedTable._rename;
42
47
  }
43
48
  return { rows: updatedRows, table: updatedTable };
@@ -86,16 +91,9 @@ exports.handleDataImport = (appId, user, table, dataImport) => __awaiter(void 0,
86
91
  ];
87
92
  }
88
93
  }
89
- // make sure link rows are up to date
90
- finalData.push(linkRows.updateLinks({
91
- appId,
92
- eventType: linkRows.EventType.ROW_SAVE,
93
- row,
94
- tableId: row.tableId,
95
- table,
96
- }));
94
+ finalData.push(row);
97
95
  }
98
- yield db.bulkDocs(yield Promise.all(finalData));
96
+ yield db.bulkDocs(finalData);
99
97
  let response = yield db.put(table);
100
98
  table._rev = response._rev;
101
99
  }
@@ -204,4 +202,79 @@ exports.getExternalTable = (appId, datasourceId, tableName) => __awaiter(void 0,
204
202
  const entities = yield exports.getAllExternalTables(appId, datasourceId);
205
203
  return entities[tableName];
206
204
  });
205
+ exports.getTable = (appId, tableId) => __awaiter(void 0, void 0, void 0, function* () {
206
+ const db = new CouchDB(appId);
207
+ if (isExternalTable(tableId)) {
208
+ let { datasourceId, tableName } = breakExternalTableId(tableId);
209
+ return exports.getExternalTable(appId, datasourceId, tableName);
210
+ }
211
+ else {
212
+ return db.get(tableId);
213
+ }
214
+ });
215
+ exports.checkForViewUpdates = (db, table, rename, deletedColumns) => __awaiter(void 0, void 0, void 0, function* () {
216
+ const views = yield getViews(db);
217
+ const tableViews = views.filter(view => view.meta.tableId === table._id);
218
+ // Check each table view to see if impacted by this table action
219
+ for (let view of tableViews) {
220
+ let needsUpdated = false;
221
+ // First check for renames, otherwise check for deletions
222
+ if (rename) {
223
+ // Update calculation field if required
224
+ if (view.meta.field === rename.old) {
225
+ view.meta.field = rename.updated;
226
+ needsUpdated = true;
227
+ }
228
+ // Update group by field if required
229
+ if (view.meta.groupBy === rename.old) {
230
+ view.meta.groupBy = rename.updated;
231
+ needsUpdated = true;
232
+ }
233
+ // Update filters if required
234
+ if (view.meta.filters) {
235
+ view.meta.filters.forEach(filter => {
236
+ if (filter.key === rename.old) {
237
+ filter.key = rename.updated;
238
+ needsUpdated = true;
239
+ }
240
+ });
241
+ }
242
+ }
243
+ else if (deletedColumns) {
244
+ deletedColumns.forEach(column => {
245
+ // Remove calculation statement if required
246
+ if (view.meta.field === column) {
247
+ delete view.meta.field;
248
+ delete view.meta.calculation;
249
+ delete view.meta.groupBy;
250
+ needsUpdated = true;
251
+ }
252
+ // Remove group by field if required
253
+ if (view.meta.groupBy === column) {
254
+ delete view.meta.groupBy;
255
+ needsUpdated = true;
256
+ }
257
+ // Remove filters referencing deleted field if required
258
+ if (view.meta.filters && view.meta.filters.length) {
259
+ const initialLength = view.meta.filters.length;
260
+ view.meta.filters = view.meta.filters.filter(filter => {
261
+ return filter.key !== column;
262
+ });
263
+ if (initialLength !== view.meta.filters.length) {
264
+ needsUpdated = true;
265
+ }
266
+ }
267
+ });
268
+ }
269
+ // Update view if required
270
+ if (needsUpdated) {
271
+ const newViewTemplate = viewTemplate(view.meta);
272
+ yield saveView(db, null, view.name, newViewTemplate);
273
+ if (!newViewTemplate.meta.schema) {
274
+ newViewTemplate.meta.schema = table.schema;
275
+ }
276
+ table.views[view.name] = newViewTemplate.meta;
277
+ }
278
+ }
279
+ });
207
280
  exports.TableSaveFunctions = TableSaveFunctions;
@@ -15,9 +15,24 @@ const DEFAULT_TEMPLATES_BUCKET = "prod-budi-templates.s3-eu-west-1.amazonaws.com
15
15
  exports.fetch = function (ctx) {
16
16
  return __awaiter(this, void 0, void 0, function* () {
17
17
  const { type = "app" } = ctx.query;
18
- const response = yield fetch(`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`);
19
- const json = yield response.json();
20
- ctx.body = Object.values(json.templates[type]);
18
+ let response, error = false;
19
+ try {
20
+ response = yield fetch(`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`);
21
+ if (response.status !== 200) {
22
+ error = true;
23
+ }
24
+ }
25
+ catch (err) {
26
+ error = true;
27
+ }
28
+ // if there is an error, simply return no templates
29
+ if (!error && response) {
30
+ const json = yield response.json();
31
+ ctx.body = Object.values(json.templates[type]);
32
+ }
33
+ else {
34
+ ctx.body = [];
35
+ }
21
36
  });
22
37
  };
23
38
  // can't currently test this, have to ignore from coverage
@@ -10,6 +10,14 @@ const TOKEN_MAP = {
10
10
  AND: "&&",
11
11
  OR: "||",
12
12
  };
13
+ const isEmptyExpression = key => {
14
+ return `(
15
+ doc["${key}"] === undefined ||
16
+ doc["${key}"] === null ||
17
+ doc["${key}"] === "" ||
18
+ (Array.isArray(doc["${key}"]) && doc["${key}"].length === 0)
19
+ )`;
20
+ };
13
21
  const GROUP_PROPERTY = {
14
22
  group: {
15
23
  type: "string",
@@ -66,6 +74,12 @@ function parseFilterExpression(filters) {
66
74
  if (filter.condition === "CONTAINS") {
67
75
  expression.push(`doc["${filter.key}"].${TOKEN_MAP[filter.condition]}("${filter.value}")`);
68
76
  }
77
+ else if (filter.condition === "EMPTY") {
78
+ expression.push(isEmptyExpression(filter.key));
79
+ }
80
+ else if (filter.condition === "NOT_EMPTY") {
81
+ expression.push(`!${isEmptyExpression(filter.key)}`);
82
+ }
69
83
  else {
70
84
  const value = typeof filter.value == "string" ? `"${filter.value}"` : filter.value;
71
85
  expression.push(`doc["${filter.key}"] ${TOKEN_MAP[filter.condition]} ${value}`);
@@ -100,7 +114,7 @@ function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) {
100
114
  delete filters[0].conjunction;
101
115
  }
102
116
  const parsedFilters = parseFilterExpression(filters);
103
- const filterExpression = parsedFilters ? `&& ${parsedFilters}` : "";
117
+ const filterExpression = parsedFilters ? `&& (${parsedFilters})` : "";
104
118
  const emitExpression = parseEmitExpression(field, groupBy);
105
119
  const reduction = field && calculation ? { reduce: `_${calculation}` } : {};
106
120
  let schema = null;
@@ -6,6 +6,7 @@ const { BUILDER } = require("@budibase/auth/permissions");
6
6
  const usage = require("../../middleware/usageQuota");
7
7
  const router = Router();
8
8
  router
9
+ .post("/api/applications/:appId/sync", authorized(BUILDER), controller.sync)
9
10
  .post("/api/applications", authorized(BUILDER), usage, controller.create)
10
11
  .get("/api/applications/:appId/definition", controller.fetchAppDefinition)
11
12
  .get("/api/applications", controller.fetch)
@@ -5,11 +5,15 @@ const env = require("../../environment");
5
5
  const authorized = require("../../middleware/authorized");
6
6
  const { BUILDER } = require("@budibase/auth/permissions");
7
7
  const router = Router();
8
- if (env.isDev() || env.isTest()) {
8
+ function redirectPath(path) {
9
9
  router
10
- .get("/api/global/:devPath(.*)", controller.redirectGet)
11
- .post("/api/global/:devPath(.*)", controller.redirectPost)
12
- .delete("/api/global/:devPath(.*)", controller.redirectDelete);
10
+ .get(`/api/${path}/:devPath(.*)`, controller.buildRedirectGet(path))
11
+ .post(`/api/${path}/:devPath(.*)`, controller.buildRedirectPost(path))
12
+ .delete(`/api/${path}/:devPath(.*)`, controller.buildRedirectDelete(path));
13
+ }
14
+ if (env.isDev() || env.isTest()) {
15
+ redirectPath("global");
16
+ redirectPath("system");
13
17
  }
14
18
  router
15
19
  .get("/api/dev/version", authorized(BUILDER), controller.getBudibaseVersion)
@@ -22,7 +22,8 @@ function generateQueryValidation() {
22
22
  })),
23
23
  queryVerb: Joi.string().allow().required(),
24
24
  extra: Joi.object().optional(),
25
- schema: Joi.object({}).required().unknown(true)
25
+ schema: Joi.object({}).required().unknown(true),
26
+ transformer: Joi.string().optional(),
26
27
  }));
27
28
  }
28
29
  function generateQueryPreviewValidation() {
@@ -32,6 +33,7 @@ function generateQueryPreviewValidation() {
32
33
  queryVerb: Joi.string().allow().required(),
33
34
  extra: Joi.object().optional(),
34
35
  datasourceId: Joi.string().required(),
36
+ transformer: Joi.string().optional(),
35
37
  parameters: Joi.object({}).required().unknown(true)
36
38
  }));
37
39
  }
@@ -57,9 +57,10 @@ exports.createRequest = (request, method, url, body) => {
57
57
  return req;
58
58
  };
59
59
  exports.checkBuilderEndpoint = ({ config, method, url, body }) => __awaiter(void 0, void 0, void 0, function* () {
60
- const headers = yield config.login("test@test.com", "test", {
60
+ const headers = yield config.login({
61
61
  userId: "us_fail",
62
62
  builder: false,
63
+ prodApp: true,
63
64
  });
64
65
  yield exports
65
66
  .createRequest(config.request, method, url, body)
@@ -67,11 +68,9 @@ exports.checkBuilderEndpoint = ({ config, method, url, body }) => __awaiter(void
67
68
  .expect(403);
68
69
  });
69
70
  exports.checkPermissionsEndpoint = ({ config, method, url, body, passRole, failRole, }) => __awaiter(void 0, void 0, void 0, function* () {
70
- const password = "PASSWORD";
71
- let user = yield config.createUser("pass@budibase.com", password, passRole);
72
- const passHeader = yield config.login("pass@budibase.com", password, {
71
+ const passHeader = yield config.login({
73
72
  roleId: passRole,
74
- userId: user.globalId,
73
+ prodApp: true,
75
74
  });
76
75
  yield exports
77
76
  .createRequest(config.request, method, url, body)
@@ -79,14 +78,13 @@ exports.checkPermissionsEndpoint = ({ config, method, url, body, passRole, failR
79
78
  .expect(200);
80
79
  let failHeader;
81
80
  if (failRole === BUILTIN_ROLE_IDS.PUBLIC) {
82
- failHeader = config.publicHeaders();
81
+ failHeader = config.publicHeaders({ prodApp: true });
83
82
  }
84
83
  else {
85
- user = yield config.createUser("fail@budibase.com", password, failRole);
86
- failHeader = yield config.login("fail@budibase.com", password, {
84
+ failHeader = yield config.login({
87
85
  roleId: failRole,
88
- userId: user.globalId,
89
86
  builder: false,
87
+ prodApp: true,
90
88
  });
91
89
  }
92
90
  yield exports
@@ -13,7 +13,6 @@ const createRow = require("./steps/createRow");
13
13
  const updateRow = require("./steps/updateRow");
14
14
  const deleteRow = require("./steps/deleteRow");
15
15
  const executeScript = require("./steps/executeScript");
16
- const bash = require("./steps/bash");
17
16
  const executeQuery = require("./steps/executeQuery");
18
17
  const outgoingWebhook = require("./steps/outgoingWebhook");
19
18
  const serverLog = require("./steps/serverLog");
@@ -24,6 +23,7 @@ const integromat = require("./steps/integromat");
24
23
  let filter = require("./steps/filter");
25
24
  let delay = require("./steps/delay");
26
25
  let queryRow = require("./steps/queryRows");
26
+ const env = require("../environment");
27
27
  const ACTION_IMPLS = {
28
28
  SEND_EMAIL_SMTP: sendSmtpEmail.run,
29
29
  CREATE_ROW: createRow.run,
@@ -31,7 +31,6 @@ const ACTION_IMPLS = {
31
31
  DELETE_ROW: deleteRow.run,
32
32
  OUTGOING_WEBHOOK: outgoingWebhook.run,
33
33
  EXECUTE_SCRIPT: executeScript.run,
34
- EXECUTE_BASH: bash.run,
35
34
  EXECUTE_QUERY: executeQuery.run,
36
35
  SERVER_LOG: serverLog.run,
37
36
  DELAY: delay.run,
@@ -51,7 +50,6 @@ const ACTION_DEFINITIONS = {
51
50
  OUTGOING_WEBHOOK: outgoingWebhook.definition,
52
51
  EXECUTE_SCRIPT: executeScript.definition,
53
52
  EXECUTE_QUERY: executeQuery.definition,
54
- EXECUTE_BASH: bash.definition,
55
53
  SERVER_LOG: serverLog.definition,
56
54
  DELAY: delay.definition,
57
55
  FILTER: filter.definition,
@@ -62,6 +60,14 @@ const ACTION_DEFINITIONS = {
62
60
  zapier: zapier.definition,
63
61
  integromat: integromat.definition,
64
62
  };
63
+ // don't add the bash script/definitions unless in self host
64
+ // the fact this isn't included in any definitions means it cannot be
65
+ // ran at all
66
+ if (env.SELF_HOSTED) {
67
+ const bash = require("./steps/bash");
68
+ ACTION_IMPLS["EXECUTE_BASH"] = bash.run;
69
+ ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition;
70
+ }
65
71
  /* istanbul ignore next */
66
72
  exports.getAction = function (actionName) {
67
73
  return __awaiter(this, void 0, void 0, function* () {
@@ -8,9 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- const CouchDB = require("../db");
12
- const { isExternalTable, breakExternalTableId, } = require("../integrations/utils");
13
- const { getExternalTable } = require("../api/controllers/table/utils");
11
+ const { getTable } = require("../api/controllers/table/utils");
14
12
  /**
15
13
  * When values are input to the system generally they will be of type string as this is required for template strings.
16
14
  * This can generate some odd scenarios as the Schema of the automation requires a number but the builder might supply
@@ -27,7 +25,7 @@ const { getExternalTable } = require("../api/controllers/table/utils");
27
25
  * @returns {object} The inputs object which has had all the various types supported by this function converted to their
28
26
  * primitive types.
29
27
  */
30
- module.exports.cleanInputValues = (inputs, schema) => {
28
+ exports.cleanInputValues = (inputs, schema) => {
31
29
  if (schema == null) {
32
30
  return inputs;
33
31
  }
@@ -68,29 +66,10 @@ module.exports.cleanInputValues = (inputs, schema) => {
68
66
  * @param {object} row The input row structure which requires clean-up after having been through template statements.
69
67
  * @returns {Promise<Object>} The cleaned up rows object, will should now have all the required primitive types.
70
68
  */
71
- module.exports.cleanUpRow = (appId, tableId, row) => __awaiter(void 0, void 0, void 0, function* () {
72
- const db = new CouchDB(appId);
73
- let table;
74
- if (isExternalTable(tableId)) {
75
- const { datasourceId, tableName } = breakExternalTableId(tableId);
76
- table = yield getExternalTable(appId, datasourceId, tableName);
77
- }
78
- else {
79
- table = yield db.get(tableId);
80
- }
81
- return module.exports.cleanInputValues(row, { properties: table.schema });
82
- });
83
- /**
84
- * A utility function for the cleanUpRow, which can be used if only the row ID is known (not the table ID) to clean
85
- * up a row after template statements have been replaced. This is specifically useful for the update row action.
86
- *
87
- * @param {string} appId The instance which the Table/Table is contained under.
88
- * @param {string} rowId The ID of the row from which the tableId will be extracted, to get the Table/Table schema.
89
- * @param {object} row The input row structure which requires clean-up after having been through template statements.
90
- * @returns {Promise<Object>} The cleaned up rows object, which will now have all the required primitive types.
91
- */
92
- module.exports.cleanUpRowById = (appId, rowId, row) => __awaiter(void 0, void 0, void 0, function* () {
93
- const db = new CouchDB(appId);
94
- const foundRow = yield db.get(rowId);
95
- return module.exports.cleanUpRow(appId, foundRow.tableId, row);
69
+ exports.cleanUpRow = (appId, tableId, row) => __awaiter(void 0, void 0, void 0, function* () {
70
+ let table = yield getTable(appId, tableId);
71
+ return exports.cleanInputValues(row, { properties: table.schema });
96
72
  });
73
+ exports.getError = err => {
74
+ return typeof err !== "string" ? err.toString() : err;
75
+ };
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const { execSync } = require("child_process");
12
12
  const { processStringSync } = require("@budibase/string-templates");
13
+ const automationUtils = require("../automationUtils");
13
14
  exports.definition = {
14
15
  name: "Bash Scripting",
15
16
  tagline: "Execute a bash command",
@@ -70,7 +71,7 @@ exports.run = function ({ inputs, context }) {
70
71
  catch (err) {
71
72
  return {
72
73
  success: false,
73
- response: err,
74
+ response: automationUtils.getError(err),
74
75
  };
75
76
  }
76
77
  });
@@ -102,7 +102,7 @@ exports.run = function ({ inputs, appId, emitter }) {
102
102
  catch (err) {
103
103
  return {
104
104
  success: false,
105
- response: err,
105
+ response: automationUtils.getError(err),
106
106
  };
107
107
  }
108
108
  });
@@ -12,6 +12,7 @@ const rowController = require("../../api/controllers/row");
12
12
  const env = require("../../environment");
13
13
  const usage = require("../../utilities/usageQuota");
14
14
  const { buildCtx } = require("./utils");
15
+ const automationUtils = require("../automationUtils");
15
16
  exports.definition = {
16
17
  description: "Delete a row from your database",
17
18
  icon: "TableRowRemoveCenter",
@@ -93,7 +94,7 @@ exports.run = function ({ inputs, appId, emitter }) {
93
94
  catch (err) {
94
95
  return {
95
96
  success: false,
96
- response: err,
97
+ response: automationUtils.getError(err),
97
98
  };
98
99
  }
99
100
  });
@@ -21,6 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  };
22
22
  const queryController = require("../../api/controllers/query");
23
23
  const { buildCtx } = require("./utils");
24
+ const automationUtils = require("../automationUtils");
24
25
  exports.definition = {
25
26
  name: "External Data Connector",
26
27
  tagline: "Execute Data Connector",
@@ -92,7 +93,7 @@ exports.run = function ({ inputs, appId, emitter }) {
92
93
  catch (err) {
93
94
  return {
94
95
  success: false,
95
- response: err,
96
+ response: automationUtils.getError(err),
96
97
  };
97
98
  }
98
99
  });
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const scriptController = require("../../api/controllers/script");
12
12
  const { buildCtx } = require("./utils");
13
+ const automationUtils = require("../automationUtils");
13
14
  exports.definition = {
14
15
  name: "JS Scripting",
15
16
  tagline: "Execute JavaScript Code",
@@ -71,7 +72,7 @@ exports.run = function ({ inputs, appId, context, emitter }) {
71
72
  catch (err) {
72
73
  return {
73
74
  success: false,
74
- response: err,
75
+ response: automationUtils.getError(err),
75
76
  };
76
77
  }
77
78
  });
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const fetch = require("node-fetch");
12
12
  const { getFetchResponse } = require("./utils");
13
+ const automationUtils = require("../automationUtils");
13
14
  const RequestType = {
14
15
  POST: "POST",
15
16
  GET: "GET",
@@ -130,7 +131,7 @@ exports.run = function ({ inputs }) {
130
131
  /* istanbul ignore next */
131
132
  return {
132
133
  success: false,
133
- response: err,
134
+ response: automationUtils.getError(err),
134
135
  };
135
136
  }
136
137
  });