@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
@@ -1,9 +1,4 @@
1
- const CouchDB = require("../db")
2
- const {
3
- isExternalTable,
4
- breakExternalTableId,
5
- } = require("../integrations/utils")
6
- const { getExternalTable } = require("../api/controllers/table/utils")
1
+ const { getTable } = require("../api/controllers/table/utils")
7
2
 
8
3
  /**
9
4
  * When values are input to the system generally they will be of type string as this is required for template strings.
@@ -21,7 +16,7 @@ const { getExternalTable } = require("../api/controllers/table/utils")
21
16
  * @returns {object} The inputs object which has had all the various types supported by this function converted to their
22
17
  * primitive types.
23
18
  */
24
- module.exports.cleanInputValues = (inputs, schema) => {
19
+ exports.cleanInputValues = (inputs, schema) => {
25
20
  if (schema == null) {
26
21
  return inputs
27
22
  }
@@ -63,30 +58,11 @@ module.exports.cleanInputValues = (inputs, schema) => {
63
58
  * @param {object} row The input row structure which requires clean-up after having been through template statements.
64
59
  * @returns {Promise<Object>} The cleaned up rows object, will should now have all the required primitive types.
65
60
  */
66
- module.exports.cleanUpRow = async (appId, tableId, row) => {
67
- const db = new CouchDB(appId)
68
- let table
69
- if (isExternalTable(tableId)) {
70
- const { datasourceId, tableName } = breakExternalTableId(tableId)
71
- table = await getExternalTable(appId, datasourceId, tableName)
72
- } else {
73
- table = await db.get(tableId)
74
- }
75
-
76
- return module.exports.cleanInputValues(row, { properties: table.schema })
61
+ exports.cleanUpRow = async (appId, tableId, row) => {
62
+ let table = await getTable(appId, tableId)
63
+ return exports.cleanInputValues(row, { properties: table.schema })
77
64
  }
78
65
 
79
- /**
80
- * A utility function for the cleanUpRow, which can be used if only the row ID is known (not the table ID) to clean
81
- * up a row after template statements have been replaced. This is specifically useful for the update row action.
82
- *
83
- * @param {string} appId The instance which the Table/Table is contained under.
84
- * @param {string} rowId The ID of the row from which the tableId will be extracted, to get the Table/Table schema.
85
- * @param {object} row The input row structure which requires clean-up after having been through template statements.
86
- * @returns {Promise<Object>} The cleaned up rows object, which will now have all the required primitive types.
87
- */
88
- module.exports.cleanUpRowById = async (appId, rowId, row) => {
89
- const db = new CouchDB(appId)
90
- const foundRow = await db.get(rowId)
91
- return module.exports.cleanUpRow(appId, foundRow.tableId, row)
66
+ exports.getError = err => {
67
+ return typeof err !== "string" ? err.toString() : err
92
68
  }
@@ -1,5 +1,6 @@
1
1
  const { execSync } = require("child_process")
2
2
  const { processStringSync } = require("@budibase/string-templates")
3
+ const automationUtils = require("../automationUtils")
3
4
 
4
5
  exports.definition = {
5
6
  name: "Bash Scripting",
@@ -63,7 +64,7 @@ exports.run = async function ({ inputs, context }) {
63
64
  } catch (err) {
64
65
  return {
65
66
  success: false,
66
- response: err,
67
+ response: automationUtils.getError(err),
67
68
  }
68
69
  }
69
70
  }
@@ -97,7 +97,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
97
97
  } catch (err) {
98
98
  return {
99
99
  success: false,
100
- response: err,
100
+ response: automationUtils.getError(err),
101
101
  }
102
102
  }
103
103
  }
@@ -2,6 +2,7 @@ const rowController = require("../../api/controllers/row")
2
2
  const env = require("../../environment")
3
3
  const usage = require("../../utilities/usageQuota")
4
4
  const { buildCtx } = require("./utils")
5
+ const automationUtils = require("../automationUtils")
5
6
 
6
7
  exports.definition = {
7
8
  description: "Delete a row from your database",
@@ -85,7 +86,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
85
86
  } catch (err) {
86
87
  return {
87
88
  success: false,
88
- response: err,
89
+ response: automationUtils.getError(err),
89
90
  }
90
91
  }
91
92
  }
@@ -1,5 +1,6 @@
1
1
  const queryController = require("../../api/controllers/query")
2
2
  const { buildCtx } = require("./utils")
3
+ const automationUtils = require("../automationUtils")
3
4
 
4
5
  exports.definition = {
5
6
  name: "External Data Connector",
@@ -74,7 +75,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
74
75
  } catch (err) {
75
76
  return {
76
77
  success: false,
77
- response: err,
78
+ response: automationUtils.getError(err),
78
79
  }
79
80
  }
80
81
  }
@@ -1,5 +1,6 @@
1
1
  const scriptController = require("../../api/controllers/script")
2
2
  const { buildCtx } = require("./utils")
3
+ const automationUtils = require("../automationUtils")
3
4
 
4
5
  exports.definition = {
5
6
  name: "JS Scripting",
@@ -63,7 +64,7 @@ exports.run = async function ({ inputs, appId, context, emitter }) {
63
64
  } catch (err) {
64
65
  return {
65
66
  success: false,
66
- response: err,
67
+ response: automationUtils.getError(err),
67
68
  }
68
69
  }
69
70
  }
@@ -1,5 +1,6 @@
1
1
  const fetch = require("node-fetch")
2
2
  const { getFetchResponse } = require("./utils")
3
+ const automationUtils = require("../automationUtils")
3
4
 
4
5
  const RequestType = {
5
6
  POST: "POST",
@@ -127,7 +128,7 @@ exports.run = async function ({ inputs }) {
127
128
  /* istanbul ignore next */
128
129
  return {
129
130
  success: false,
130
- response: err,
131
+ response: automationUtils.getError(err),
131
132
  }
132
133
  }
133
134
  }
@@ -2,6 +2,7 @@ const rowController = require("../../api/controllers/row")
2
2
  const tableController = require("../../api/controllers/table")
3
3
  const { FieldTypes } = require("../../constants")
4
4
  const { buildCtx } = require("./utils")
5
+ const automationUtils = require("../automationUtils")
5
6
 
6
7
  const SortOrders = {
7
8
  ASCENDING: "ascending",
@@ -110,7 +111,7 @@ exports.run = async function ({ inputs, appId }) {
110
111
  } catch (err) {
111
112
  return {
112
113
  success: false,
113
- response: err,
114
+ response: automationUtils.getError(err),
114
115
  }
115
116
  }
116
117
  }
@@ -1,4 +1,5 @@
1
1
  const { sendSmtpEmail } = require("../../utilities/workerRequests")
2
+ const automationUtils = require("../automationUtils")
2
3
 
3
4
  exports.definition = {
4
5
  description: "Send an email using SMTP",
@@ -61,7 +62,7 @@ exports.run = async function ({ inputs }) {
61
62
  } catch (err) {
62
63
  return {
63
64
  success: false,
64
- response: err,
65
+ response: automationUtils.getError(err),
65
66
  }
66
67
  }
67
68
  }
@@ -64,6 +64,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
64
64
  },
65
65
  }
66
66
  }
67
+ const tableId = inputs.row.tableId
67
68
 
68
69
  // clear any falsy properties so that they aren't updated
69
70
  for (let propKey of Object.keys(inputs.row)) {
@@ -80,15 +81,14 @@ exports.run = async function ({ inputs, appId, emitter }) {
80
81
  },
81
82
  params: {
82
83
  rowId: inputs.rowId,
84
+ tableId: tableId,
83
85
  },
84
86
  })
85
87
 
86
88
  try {
87
- inputs.row = await automationUtils.cleanUpRowById(
88
- appId,
89
- inputs.rowId,
90
- inputs.row
91
- )
89
+ if (tableId) {
90
+ inputs.row = await automationUtils.cleanUpRow(appId, tableId, inputs.row)
91
+ }
92
92
  await rowController.patch(ctx)
93
93
  return {
94
94
  row: ctx.body,
@@ -100,7 +100,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
100
100
  } catch (err) {
101
101
  return {
102
102
  success: false,
103
- response: err,
103
+ response: automationUtils.getError(err),
104
104
  }
105
105
  }
106
106
  }
@@ -10,6 +10,7 @@ const env = require("../environment")
10
10
  const usage = require("../utilities/usageQuota")
11
11
 
12
12
  const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId
13
+ const STOPPED_STATUS = { success: false, status: "STOPPED" }
13
14
 
14
15
  /**
15
16
  * The automation orchestrator is a class responsible for executing automations.
@@ -68,7 +69,13 @@ class Orchestrator {
68
69
  async execute() {
69
70
  let automation = this._automation
70
71
  const app = await this.getApp()
72
+ let stopped = false
71
73
  for (let step of automation.definition.steps) {
74
+ // execution stopped, record state for that
75
+ if (stopped) {
76
+ this.updateExecutionOutput(step.id, step.stepId, {}, STOPPED_STATUS)
77
+ continue
78
+ }
72
79
  let stepFn = await this.getStepFunctionality(step.stepId)
73
80
  step.inputs = await processObject(step.inputs, this._context)
74
81
  step.inputs = automationUtils.cleanInputValues(
@@ -86,10 +93,17 @@ class Orchestrator {
86
93
  context: this._context,
87
94
  })
88
95
  })
96
+ this._context.steps.push(outputs)
97
+ // if filter causes us to stop execution don't break the loop, set a var
98
+ // so that we can finish iterating through the steps and record that it stopped
89
99
  if (step.stepId === FILTER_STEP_ID && !outputs.success) {
90
- break
100
+ stopped = true
101
+ this.updateExecutionOutput(step.id, step.stepId, step.inputs, {
102
+ ...outputs,
103
+ ...STOPPED_STATUS,
104
+ })
105
+ continue
91
106
  }
92
- this._context.steps.push(outputs)
93
107
  this.updateExecutionOutput(step.id, step.stepId, step.inputs, outputs)
94
108
  } catch (err) {
95
109
  console.error(`Automation error - ${step.stepId} - ${err}`)
@@ -99,7 +113,7 @@ class Orchestrator {
99
113
 
100
114
  // Increment quota for automation runs
101
115
  if (!env.SELF_HOSTED && !isDevAppID(this._appId)) {
102
- usage.update(usage.Properties.AUTOMATION, 1)
116
+ await usage.update(usage.Properties.AUTOMATION, 1)
103
117
  }
104
118
  return this.executionOutput
105
119
  }
@@ -42,6 +42,7 @@ exports.FieldTypes = {
42
42
  FORMULA: "formula",
43
43
  AUTO: "auto",
44
44
  JSON: "json",
45
+ INTERNAL: "internal",
45
46
  }
46
47
 
47
48
  exports.RelationshipTypes = {
@@ -81,7 +81,9 @@ async function getFullLinkedDocs(ctx, appId, links) {
81
81
  row => row.doc
82
82
  )
83
83
  // convert the unique db rows back to a full list of linked rows
84
- const linked = linkedRowIds.map(id => dbRows.find(row => row._id === id))
84
+ const linked = linkedRowIds
85
+ .map(id => dbRows.find(row => row && row._id === id))
86
+ .filter(row => row != null)
85
87
  // need to handle users as specific cases
86
88
  let [users, other] = partition(linked, linkRow =>
87
89
  linkRow._id.startsWith(USER_METDATA_PREFIX)
@@ -172,13 +174,18 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
172
174
  row[link.fieldName] = []
173
175
  }
174
176
  const linkedRow = linked.find(row => row._id === link.id)
175
- const linkedTableId =
176
- linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
177
- const linkedTable = await getLinkedTable(db, linkedTableId, linkedTables)
178
- if (!linkedRow || !linkedTable) {
179
- continue
177
+ if (linkedRow) {
178
+ const linkedTableId =
179
+ linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
180
+ const linkedTable = await getLinkedTable(
181
+ db,
182
+ linkedTableId,
183
+ linkedTables
184
+ )
185
+ if (linkedTable) {
186
+ row[link.fieldName].push(processFormulas(linkedTable, linkedRow))
187
+ }
180
188
  }
181
- row[link.fieldName].push(processFormulas(linkedTable, linkedRow))
182
189
  }
183
190
  }
184
191
  return rows
@@ -98,7 +98,9 @@ function addFilters(
98
98
  }
99
99
 
100
100
  function addRelationships(
101
+ knex: Knex,
101
102
  query: KnexQuery,
103
+ fields: string | string[],
102
104
  fromTable: string,
103
105
  relationships: RelationshipsJson[] | undefined
104
106
  ): KnexQuery {
@@ -114,7 +116,7 @@ function addRelationships(
114
116
  query = query.leftJoin(
115
117
  toTable,
116
118
  `${fromTable}.${from}`,
117
- `${relationship.tableName}.${to}`
119
+ `${toTable}.${to}`
118
120
  )
119
121
  } else {
120
122
  const throughTable = relationship.through
@@ -130,7 +132,7 @@ function addRelationships(
130
132
  .leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`)
131
133
  }
132
134
  }
133
- return query
135
+ return query.limit(BASE_LIMIT)
134
136
  }
135
137
 
136
138
  function buildCreate(
@@ -199,7 +201,13 @@ function buildRead(knex: Knex, json: QueryJson, limit: number): KnexQuery {
199
201
  [tableName]: query,
200
202
  }).select(selectStatement)
201
203
  // handle joins
202
- return addRelationships(preQuery, tableName, relationships)
204
+ return addRelationships(
205
+ knex,
206
+ preQuery,
207
+ selectStatement,
208
+ tableName,
209
+ relationships
210
+ )
203
211
  }
204
212
 
205
213
  function buildUpdate(
@@ -10,7 +10,7 @@ import { Table, TableSchema } from "../definitions/common"
10
10
  import { getSqlQuery } from "./utils"
11
11
 
12
12
  module MySQLModule {
13
- const mysql = require("mysql")
13
+ const mysql = require("mysql2")
14
14
  const Sql = require("./base/sql")
15
15
  const {
16
16
  buildExternalTableId,
@@ -27,7 +27,7 @@ describe("MongoDB Integration", () => {
27
27
  const body = {
28
28
  name: "Hello"
29
29
  }
30
- const response = await config.integration.create({
30
+ await config.integration.create({
31
31
  index: indexName,
32
32
  json: body,
33
33
  extra: { collection: 'testCollection', actionTypes: 'insertOne'}
@@ -54,7 +54,7 @@ describe("MongoDB Integration", () => {
54
54
  },
55
55
  extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
56
56
  }
57
- const response = await config.integration.delete(query)
57
+ await config.integration.delete(query)
58
58
  expect(config.integration.client.deleteOne).toHaveBeenCalledWith(query.json)
59
59
  })
60
60
 
@@ -65,7 +65,7 @@ describe("MongoDB Integration", () => {
65
65
  },
66
66
  extra: { collection: 'testCollection', actionTypes: 'updateOne'}
67
67
  }
68
- const response = await config.integration.update(query)
68
+ await config.integration.update(query)
69
69
  expect(config.integration.client.updateOne).toHaveBeenCalledWith(query.json)
70
70
  })
71
71
 
@@ -75,10 +75,14 @@ describe("MongoDB Integration", () => {
75
75
  const query = {
76
76
  extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
77
77
  }
78
- // Weird, need to do an IIFE for jest to recognize that it throws
79
- expect(() => config.integration.read(query)()).toThrow(expect.any(Object))
80
78
 
79
+ let error = null
80
+ try {
81
+ await config.integration.read(query)
82
+ } catch (err) {
83
+ error = err
84
+ }
85
+ expect(error).toBeDefined()
81
86
  restore()
82
87
  })
83
-
84
88
  })
@@ -1,5 +1,5 @@
1
1
  const MySQLIntegration = require("../mysql")
2
- jest.mock("mysql")
2
+ jest.mock("mysql2")
3
3
 
4
4
  class TestConfiguration {
5
5
  constructor(config = { ssl: {} }) {
@@ -5,6 +5,7 @@ const { DocumentTypes, SEPARATOR } = require("../db/utils")
5
5
  const { FieldTypes } = require("../constants")
6
6
 
7
7
  const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
8
+ const ROW_ID_REGEX = /^\[.*]$/g
8
9
 
9
10
  export function isExternalTable(tableId: string) {
10
11
  return tableId.includes(DocumentTypes.DATASOURCE)
@@ -32,6 +33,23 @@ export function generateRowIdField(keyProps: any[] = []) {
32
33
  return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"))
33
34
  }
34
35
 
36
+ export function isRowId(field: any) {
37
+ return (
38
+ Array.isArray(field) ||
39
+ (typeof field === "string" && field.match(ROW_ID_REGEX) != null)
40
+ )
41
+ }
42
+
43
+ export function convertRowId(field: any) {
44
+ if (Array.isArray(field)) {
45
+ return field[0]
46
+ }
47
+ if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
48
+ return field.substring(1, field.length - 1)
49
+ }
50
+ return field
51
+ }
52
+
35
53
  // should always return an array
36
54
  export function breakRowIdField(_id: string | { _id: string }): any[] {
37
55
  if (!_id) {
@@ -3,7 +3,7 @@ const { getAppId, setCookie, getCookie, clearCookie } =
3
3
  const { Cookies } = require("@budibase/auth").constants
4
4
  const { getRole } = require("@budibase/auth/roles")
5
5
  const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
6
- const { generateUserMetadataID } = require("../db/utils")
6
+ const { generateUserMetadataID, isDevAppID } = require("../db/utils")
7
7
  const { dbExists } = require("@budibase/auth/db")
8
8
  const { isUserInAppTenant } = require("@budibase/auth/tenancy")
9
9
  const { getCachedSelf } = require("../utilities/global")
@@ -35,6 +35,15 @@ module.exports = async (ctx, next) => {
35
35
  requestAppId = requestAppId || appId
36
36
  }
37
37
 
38
+ // deny access to application preview
39
+ if (
40
+ isDevAppID(requestAppId) &&
41
+ (!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
42
+ ) {
43
+ clearCookie(ctx, Cookies.CurrentApp)
44
+ return ctx.redirect("/")
45
+ }
46
+
38
47
  let appId,
39
48
  roleId = BUILTIN_ROLE_IDS.PUBLIC
40
49
  if (!ctx.user) {
@@ -45,7 +54,7 @@ module.exports = async (ctx, next) => {
45
54
  const globalUser = await getCachedSelf(ctx, requestAppId)
46
55
  appId = requestAppId
47
56
  // retrieving global user gets the right role
48
- roleId = globalUser.roleId || BUILTIN_ROLE_IDS.BASIC
57
+ roleId = globalUser.roleId || roleId
49
58
  }
50
59
 
51
60
  // nothing more to do
@@ -127,8 +127,8 @@ describe("Current app middleware", () => {
127
127
  } else {
128
128
  expect(cookieFn).not.toHaveBeenCalled()
129
129
  }
130
- expect(config.ctx.roleId).toEqual("BASIC")
131
- expect(config.ctx.user.role._id).toEqual("BASIC")
130
+ expect(config.ctx.roleId).toEqual("PUBLIC")
131
+ expect(config.ctx.user.role._id).toEqual("PUBLIC")
132
132
  expect(config.ctx.appId).toEqual("app_test")
133
133
  expect(config.next).toHaveBeenCalled()
134
134
  }
@@ -163,7 +163,7 @@ describe("Current app middleware", () => {
163
163
  return "app_test"
164
164
  },
165
165
  setCookie: jest.fn(),
166
- getCookie: () => ({appId: "app_test", roleId: "BASIC"}),
166
+ getCookie: () => ({appId: "app_test", roleId: "PUBLIC"}),
167
167
  },
168
168
  constants: { Cookies: {} },
169
169
  }))
@@ -26,7 +26,6 @@ auth.init(CouchDB)
26
26
 
27
27
  const GLOBAL_USER_ID = "us_uuid1"
28
28
  const EMAIL = "babs@babs.com"
29
- const PASSWORD = "babs_password"
30
29
 
31
30
  class TestConfiguration {
32
31
  constructor(openServer = true) {
@@ -67,13 +66,18 @@ class TestConfiguration {
67
66
  return request.body
68
67
  }
69
68
 
70
- async globalUser(id = GLOBAL_USER_ID, builder = true, roles) {
69
+ async globalUser({
70
+ id = GLOBAL_USER_ID,
71
+ builder = true,
72
+ email = EMAIL,
73
+ roles,
74
+ } = {}) {
71
75
  const db = getGlobalDB(TENANT_ID)
72
76
  let existing
73
77
  try {
74
78
  existing = await db.get(id)
75
79
  } catch (err) {
76
- existing = {}
80
+ existing = { email }
77
81
  }
78
82
  const user = {
79
83
  _id: id,
@@ -84,6 +88,8 @@ class TestConfiguration {
84
88
  await createASession(id, { sessionId: "sessionid", tenantId: TENANT_ID })
85
89
  if (builder) {
86
90
  user.builder = { global: true }
91
+ } else {
92
+ user.builder = { global: false }
87
93
  }
88
94
  const resp = await db.put(user)
89
95
  return {
@@ -132,12 +138,14 @@ class TestConfiguration {
132
138
  return headers
133
139
  }
134
140
 
135
- publicHeaders() {
141
+ publicHeaders({ prodApp = true } = {}) {
142
+ const appId = prodApp ? this.prodAppId : this.appId
143
+
136
144
  const headers = {
137
145
  Accept: "application/json",
138
146
  }
139
- if (this.appId) {
140
- headers[Headers.APP_ID] = this.appId
147
+ if (appId) {
148
+ headers[Headers.APP_ID] = appId
141
149
  }
142
150
  return headers
143
151
  }
@@ -146,17 +154,37 @@ class TestConfiguration {
146
154
  email = EMAIL,
147
155
  roleId = BUILTIN_ROLE_IDS.ADMIN,
148
156
  builder = false,
149
- }) {
150
- return this.login(email, PASSWORD, { roleId, builder })
157
+ prodApp = true,
158
+ } = {}) {
159
+ return this.login({ email, roleId, builder, prodApp })
151
160
  }
152
161
 
153
162
  async createApp(appName) {
163
+ // create dev app
154
164
  this.app = await this._req({ name: appName }, null, controllers.app.create)
155
165
  this.appId = this.app.appId
166
+
167
+ // create production app
168
+ this.prodApp = await this.deploy()
169
+ this.prodAppId = this.prodApp.appId
170
+
171
+ this.allApps.push(this.prodApp)
156
172
  this.allApps.push(this.app)
173
+
157
174
  return this.app
158
175
  }
159
176
 
177
+ async deploy() {
178
+ const deployment = await this._req(null, null, controllers.deploy.deployApp)
179
+ const prodAppId = deployment.appId.replace("_dev", "")
180
+ const appPackage = await this._req(
181
+ null,
182
+ { appId: prodAppId },
183
+ controllers.app.fetchAppPackage
184
+ )
185
+ return appPackage.application
186
+ }
187
+
160
188
  async updateTable(config = null) {
161
189
  config = config || basicTable()
162
190
  this.table = await this._req(config, null, controllers.table.save)
@@ -313,9 +341,9 @@ class TestConfiguration {
313
341
  return await this._req(config, null, controllers.layout.save)
314
342
  }
315
343
 
316
- async createUser(id = null) {
344
+ async createUser(id = null, email = EMAIL) {
317
345
  const globalId = !id ? `us_${Math.random()}` : `us_${id}`
318
- const resp = await this.globalUser(globalId)
346
+ const resp = await this.globalUser({ id: globalId, email })
319
347
  await userCache.invalidateUser(globalId)
320
348
  return {
321
349
  ...resp,
@@ -323,21 +351,21 @@ class TestConfiguration {
323
351
  }
324
352
  }
325
353
 
326
- async login(email, password, { roleId, userId, builder } = {}) {
354
+ async login({ roleId, userId, builder, prodApp = false } = {}) {
355
+ const appId = prodApp ? this.prodAppId : this.appId
356
+
327
357
  userId = !userId ? `us_uuid1` : userId
328
358
  if (!this.request) {
329
359
  throw "Server has not been opened, cannot login."
330
360
  }
331
361
  // make sure the user exists in the global DB
332
362
  if (roleId !== BUILTIN_ROLE_IDS.PUBLIC) {
333
- const appId = `app${this.getAppId().split("app_dev")[1]}`
334
- await this.globalUser(userId, builder, {
335
- [appId]: roleId,
363
+ await this.globalUser({
364
+ userId,
365
+ builder,
366
+ roles: { [this.prodAppId]: roleId },
336
367
  })
337
368
  }
338
- if (!email || !password) {
339
- await this.createUser()
340
- }
341
369
  await createASession(userId, {
342
370
  sessionId: "sessionid",
343
371
  tenantId: TENANT_ID,
@@ -350,7 +378,7 @@ class TestConfiguration {
350
378
  }
351
379
  const app = {
352
380
  roleId: roleId,
353
- appId: this.appId,
381
+ appId,
354
382
  }
355
383
  const authToken = jwt.sign(auth, env.JWT_SECRET)
356
384
  const appToken = jwt.sign(app, env.JWT_SECRET)
@@ -363,7 +391,7 @@ class TestConfiguration {
363
391
  `${Cookies.Auth}=${authToken}`,
364
392
  `${Cookies.CurrentApp}=${appToken}`,
365
393
  ],
366
- [Headers.APP_ID]: this.appId,
394
+ [Headers.APP_ID]: appId,
367
395
  }
368
396
  }
369
397
  }
@@ -12,4 +12,5 @@ module.exports = {
12
12
  screen: require("../../api/controllers/screen"),
13
13
  webhook: require("../../api/controllers/webhook"),
14
14
  layout: require("../../api/controllers/layout"),
15
+ deploy: require("../../api/controllers/deploy"),
15
16
  }