@budibase/server 0.9.184 → 0.9.185-alpha.11

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 (290) hide show
  1. package/Dockerfile +1 -1
  2. package/__mocks__/mssql.ts +1 -1
  3. package/__mocks__/pg.ts +3 -0
  4. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  5. package/builder/assets/index.053c6f7a.js +1321 -0
  6. package/builder/assets/index.4a7c5636.css +1 -0
  7. package/builder/assets/vendor.470042a4.js +152 -0
  8. package/builder/assets/vendor.5e1fe644.css +1 -0
  9. package/builder/index.html +4 -4
  10. package/coverage/clover.xml +1357 -959
  11. package/coverage/coverage-final.json +91 -87
  12. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  13. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  14. package/coverage/lcov-report/api/controllers/application.js.html +65 -14
  15. package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
  16. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  17. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  20. package/coverage/lcov-report/api/controllers/datasource.js.html +147 -27
  21. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  22. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  23. package/coverage/lcov-report/api/controllers/index.html +90 -90
  24. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  26. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  27. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  28. package/coverage/lcov-report/api/controllers/query.js.html +53 -209
  29. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  30. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  31. package/coverage/lcov-report/api/controllers/row/external.js.html +12 -6
  32. package/coverage/lcov-report/api/controllers/row/index.html +26 -26
  33. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  34. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  35. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
  37. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  38. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  39. package/coverage/lcov-report/api/controllers/table/external.js.html +980 -0
  40. package/coverage/lcov-report/api/controllers/table/index.html +56 -26
  41. package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
  42. package/coverage/lcov-report/api/controllers/table/internal.js.html +545 -0
  43. package/coverage/lcov-report/api/controllers/table/utils.js.html +172 -49
  44. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  45. package/coverage/lcov-report/api/controllers/user.js.html +390 -33
  46. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.html +9 -9
  48. package/coverage/lcov-report/api/controllers/view/index.js.html +5 -5
  49. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  50. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  51. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  52. package/coverage/lcov-report/api/index.html +1 -1
  53. package/coverage/lcov-report/api/index.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  65. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/index.html +4 -4
  67. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  73. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  79. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  80. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/user.js.html +17 -2
  82. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  83. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  84. package/coverage/lcov-report/automations/actions.js.html +2 -2
  85. package/coverage/lcov-report/automations/automationUtils.js.html +3 -3
  86. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  87. package/coverage/lcov-report/automations/index.html +33 -48
  88. package/coverage/lcov-report/automations/index.js.html +2 -2
  89. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  94. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  96. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/index.html +14 -14
  98. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  100. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  101. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  106. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  109. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  111. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  115. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  116. package/coverage/lcov-report/automations/utils.js.html +42 -12
  117. package/coverage/lcov-report/constants/index.html +5 -5
  118. package/coverage/lcov-report/constants/index.js.html +49 -4
  119. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  120. package/coverage/lcov-report/constants/screens.js.html +1 -1
  121. package/coverage/lcov-report/db/client.js.html +2 -2
  122. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  123. package/coverage/lcov-report/db/index.html +2 -2
  124. package/coverage/lcov-report/db/index.js.html +1 -1
  125. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  126. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  127. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  128. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  129. package/coverage/lcov-report/db/newid.js.html +1 -1
  130. package/coverage/lcov-report/db/utils.js.html +1 -1
  131. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  132. package/coverage/lcov-report/events/index.html +6 -6
  133. package/coverage/lcov-report/events/index.js.html +1 -1
  134. package/coverage/lcov-report/events/utils.js.html +5 -5
  135. package/coverage/lcov-report/index.html +98 -83
  136. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  137. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  138. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  139. package/coverage/lcov-report/middleware/authorized.js.html +11 -8
  140. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  141. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  142. package/coverage/lcov-report/middleware/index.html +23 -23
  143. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  144. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  145. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  146. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  147. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  148. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +83 -32
  149. package/coverage/lcov-report/threads/index.html +141 -0
  150. package/coverage/lcov-report/threads/index.js.html +260 -0
  151. package/coverage/lcov-report/threads/query.js.html +269 -0
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  154. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  155. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  156. package/coverage/lcov-report/utilities/global.js.html +26 -11
  157. package/coverage/lcov-report/utilities/index.html +49 -49
  158. package/coverage/lcov-report/utilities/index.js.html +65 -17
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  160. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  167. package/coverage/lcov-report/utilities/security.js.html +3 -3
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/users.js.html +1 -1
  170. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  171. package/coverage/lcov.info +2301 -1599
  172. package/dist/api/controllers/application.js +16 -2
  173. package/dist/api/controllers/auth.js +3 -3
  174. package/dist/api/controllers/datasource.js +47 -16
  175. package/dist/api/controllers/deploy/index.js +2 -0
  176. package/dist/api/controllers/dev.js +4 -1
  177. package/dist/api/controllers/query.js +30 -58
  178. package/dist/api/controllers/row/ExternalRequest.js +37 -14
  179. package/dist/api/controllers/row/external.js +1 -0
  180. package/dist/api/controllers/row/utils.js +6 -12
  181. package/dist/api/controllers/static/index.js +1 -1
  182. package/dist/api/controllers/table/external.js +242 -0
  183. package/dist/api/controllers/table/index.js +49 -123
  184. package/dist/api/controllers/table/internal.js +150 -0
  185. package/dist/api/controllers/table/utils.js +62 -28
  186. package/dist/api/controllers/user.js +123 -11
  187. package/dist/api/routes/query.js +1 -1
  188. package/dist/api/routes/table.js +7 -1
  189. package/dist/api/routes/user.js +2 -1
  190. package/dist/app.js +2 -11
  191. package/dist/automations/bullboard.js +37 -10
  192. package/dist/automations/triggers.js +7 -3
  193. package/dist/automations/utils.js +11 -2
  194. package/dist/constants/index.js +13 -0
  195. package/dist/definitions/datasource.js +4 -0
  196. package/dist/integrations/base/IntegrationBase.js +2 -0
  197. package/dist/integrations/base/datasourcePlus.js +2 -0
  198. package/dist/integrations/base/sql.js +334 -180
  199. package/dist/integrations/base/sqlTable.js +143 -0
  200. package/dist/integrations/base/utils.js +30 -0
  201. package/dist/integrations/microsoftSqlServer.js +117 -9
  202. package/dist/integrations/mysql.js +14 -84
  203. package/dist/integrations/postgres.js +35 -28
  204. package/dist/integrations/utils.js +56 -9
  205. package/dist/middleware/authorized.js +2 -1
  206. package/dist/middleware/builder.js +4 -1
  207. package/dist/package.json +7 -6
  208. package/dist/tests/utilities/TestConfiguration.js +2 -1
  209. package/dist/{automations/thread.js → threads/automation.js} +23 -7
  210. package/dist/threads/index.js +58 -0
  211. package/dist/threads/query.js +61 -0
  212. package/dist/tsconfig.tsbuildinfo +1 -1
  213. package/dist/utilities/csvParser.js +46 -5
  214. package/dist/utilities/global.js +6 -2
  215. package/dist/utilities/index.js +18 -2
  216. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  217. package/dist/utilities/scriptRunner.js +4 -1
  218. package/package.json +8 -7
  219. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  220. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  221. package/scripts/integrations/mssql/data/setup.sql +54 -0
  222. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  223. package/scripts/integrations/mssql/reset.sh +3 -0
  224. package/scripts/likeCypress.ts +33 -0
  225. package/src/api/controllers/application.js +19 -2
  226. package/src/api/controllers/auth.js +3 -0
  227. package/src/api/controllers/datasource.js +56 -16
  228. package/src/api/controllers/deploy/index.js +2 -0
  229. package/src/api/controllers/dev.js +4 -1
  230. package/src/api/controllers/query.js +29 -81
  231. package/src/api/controllers/row/ExternalRequest.ts +47 -16
  232. package/src/api/controllers/row/external.js +2 -0
  233. package/src/api/controllers/row/utils.js +8 -11
  234. package/src/api/controllers/static/index.js +1 -1
  235. package/src/api/controllers/table/external.js +300 -0
  236. package/src/api/controllers/table/index.js +47 -137
  237. package/src/api/controllers/table/internal.js +155 -0
  238. package/src/api/controllers/table/utils.js +74 -33
  239. package/src/api/controllers/user.js +132 -13
  240. package/src/api/routes/query.js +1 -0
  241. package/src/api/routes/table.js +11 -0
  242. package/src/api/routes/tests/datasource.spec.js +2 -2
  243. package/src/api/routes/tests/misc.spec.js +5 -1
  244. package/src/api/routes/tests/query.spec.js +0 -1
  245. package/src/api/routes/user.js +5 -0
  246. package/src/app.ts +2 -10
  247. package/src/automations/bullboard.js +28 -11
  248. package/src/automations/tests/automation.spec.js +3 -4
  249. package/src/automations/triggers.js +7 -3
  250. package/src/automations/utils.js +12 -2
  251. package/src/constants/index.js +15 -0
  252. package/src/definitions/common.ts +7 -1
  253. package/src/definitions/datasource.ts +9 -3
  254. package/src/integrations/airtable.ts +2 -1
  255. package/src/integrations/arangodb.ts +2 -1
  256. package/src/integrations/base/IntegrationBase.ts +6 -0
  257. package/src/integrations/base/datasourcePlus.ts +9 -0
  258. package/src/integrations/base/sql.ts +359 -222
  259. package/src/integrations/base/sqlTable.ts +180 -0
  260. package/src/integrations/base/utils.ts +22 -0
  261. package/src/integrations/couchdb.ts +2 -1
  262. package/src/integrations/dynamodb.ts +2 -1
  263. package/src/integrations/elasticsearch.ts +2 -1
  264. package/src/integrations/microsoftSqlServer.ts +145 -13
  265. package/src/integrations/mongodb.ts +2 -1
  266. package/src/integrations/mysql.ts +20 -94
  267. package/src/integrations/postgres.ts +45 -35
  268. package/src/integrations/rest.ts +2 -1
  269. package/src/integrations/s3.ts +2 -1
  270. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  271. package/src/integrations/tests/postgres.spec.js +4 -0
  272. package/src/integrations/utils.ts +60 -8
  273. package/src/middleware/authorized.js +2 -1
  274. package/src/middleware/builder.js +4 -1
  275. package/src/tests/utilities/TestConfiguration.js +2 -1
  276. package/src/{automations/thread.js → threads/automation.js} +24 -7
  277. package/src/threads/index.js +60 -0
  278. package/src/threads/query.js +63 -0
  279. package/src/utilities/csvParser.js +48 -5
  280. package/src/utilities/global.js +7 -2
  281. package/src/utilities/index.js +18 -2
  282. package/src/utilities/queue/inMemoryQueue.js +7 -0
  283. package/src/utilities/scriptRunner.js +4 -1
  284. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  285. package/src/utilities/tests/csvParser.spec.js +3 -0
  286. package/tsconfig.json +1 -1
  287. package/builder/assets/index.34964222.js +0 -201
  288. package/builder/assets/index.7469e1e4.css +0 -29
  289. package/builder/assets/vendor.278a305c.js +0 -9
  290. 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
  };
@@ -50,9 +50,12 @@ exports.getCachedSelf = (ctx, appId) => __awaiter(void 0, void 0, void 0, functi
50
50
  const user = yield userCache.getUser(ctx.user._id);
51
51
  return processUser(appId, user);
52
52
  });
53
- exports.getGlobalUser = (appId, userId) => __awaiter(void 0, void 0, void 0, function* () {
53
+ exports.getRawGlobalUser = (userId) => __awaiter(void 0, void 0, void 0, function* () {
54
54
  const db = getGlobalDB();
55
- let user = yield db.get(getGlobalIDFromUserMetadataID(userId));
55
+ return db.get(getGlobalIDFromUserMetadataID(userId));
56
+ });
57
+ exports.getGlobalUser = (appId, userId) => __awaiter(void 0, void 0, void 0, function* () {
58
+ let user = yield exports.getRawGlobalUser(userId);
56
59
  return processUser(appId, user);
57
60
  });
58
61
  exports.getGlobalUsers = (appId = null, users = null) => __awaiter(void 0, void 0, void 0, function* () {
@@ -71,6 +74,7 @@ exports.getGlobalUsers = (appId = null, users = null) => __awaiter(void 0, void
71
74
  .filter(user => user != null)
72
75
  .map(user => {
73
76
  delete user.password;
77
+ delete user.forceResetPassword;
74
78
  return user;
75
79
  });
76
80
  if (!appId) {
@@ -52,12 +52,18 @@ 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
  */
58
- exports.clientLibraryPath = appId => {
59
+ exports.clientLibraryPath = (appId, version) => {
59
60
  if (env.isProd()) {
60
- return `${exports.objectStoreUrl()}/${sanitizeKey(appId)}/budibase-client.js`;
61
+ let url = `${exports.objectStoreUrl()}/${sanitizeKey(appId)}/budibase-client.js`;
62
+ // append app version to bust the cache
63
+ if (version) {
64
+ url += `?v=${version}`;
65
+ }
66
+ return url;
61
67
  }
62
68
  else {
63
69
  return `/api/assets/client`;
@@ -126,3 +132,13 @@ exports.stringToReadStream = string => {
126
132
  },
127
133
  });
128
134
  };
135
+ exports.doesDatabaseExist = (dbName) => __awaiter(void 0, void 0, void 0, function* () {
136
+ try {
137
+ const db = new CouchDB(dbName, { skip_setup: true });
138
+ const info = yield db.info();
139
+ return info && !info.error;
140
+ }
141
+ catch (err) {
142
+ return false;
143
+ }
144
+ });
@@ -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.184",
4
+ "version": "0.9.185-alpha.11",
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.184",
72
- "@budibase/client": "^0.9.184",
73
- "@budibase/string-templates": "^0.9.184",
71
+ "@budibase/auth": "^0.9.185-alpha.11",
72
+ "@budibase/client": "^0.9.185-alpha.11",
73
+ "@budibase/string-templates": "^0.9.185-alpha.11",
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": "4db512d87ec1a8cb90196a5428ad48e4411e1985"
153
+ "gitHead": "d6018c2c9cb114e5daa8e9e12f5ccc461e0f6f0b"
153
154
  }
@@ -0,0 +1,9 @@
1
+ FROM mcr.microsoft.com/mssql/server
2
+
3
+ ENV ACCEPT_EULA=Y
4
+ ENV SA_PASSWORD=Passw0rd
5
+
6
+ COPY ./data /
7
+
8
+ ENTRYPOINT [ "/bin/bash", "entrypoint.sh" ]
9
+ CMD [ "/opt/mssql/bin/sqlservr" ]
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if [ "$1" = '/opt/mssql/bin/sqlservr' ]; then
5
+ # If this is the container's first run, initialize the application database
6
+ if [ ! -f /tmp/app-initialized ]; then
7
+ # Initialize the application database asynchronously in a background process. This allows a) the SQL Server process to be the main process in the container, which allows graceful shutdown and other goodies, and b) us to only start the SQL Server process once, as opposed to starting, stopping, then starting it again.
8
+ function initialize_app_database() {
9
+ # Wait a bit for SQL Server to start. SQL Server's process doesn't provide a clever way to check if it's up or not, and it needs to be up before we can import the application database
10
+ sleep 30s
11
+
12
+ echo "RUNNING BUDIBASE SETUP"
13
+
14
+ #run the setup script to create the DB and the schema in the DB
15
+ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Passw0rd -i setup.sql
16
+
17
+ # Note that the container has been initialized so future starts won't wipe changes to the data
18
+ touch /tmp/app-initialized
19
+ }
20
+ initialize_app_database &
21
+ fi
22
+ fi
23
+
24
+ exec "$@"
@@ -0,0 +1,54 @@
1
+ USE master;
2
+
3
+ IF OBJECT_ID ('dbo.products', 'U') IS NOT NULL
4
+ DROP TABLE products;
5
+ GO
6
+ CREATE TABLE products
7
+ (
8
+ id int IDENTITY(1,1),
9
+ name varchar (20),
10
+ description varchar(30),
11
+ CONSTRAINT pk_products PRIMARY KEY NONCLUSTERED (id)
12
+ );
13
+
14
+ IF OBJECT_ID ('dbo.tasks', 'U') IS NOT NULL
15
+ DROP TABLE tasks;
16
+ GO
17
+ CREATE TABLE tasks
18
+ (
19
+ taskid int IDENTITY(1,1),
20
+ taskname varchar (20),
21
+ productid int,
22
+ CONSTRAINT pk_tasks PRIMARY KEY NONCLUSTERED (taskid),
23
+ CONSTRAINT fk_products FOREIGN KEY (productid) REFERENCES products (id),
24
+ );
25
+
26
+ IF OBJECT_ID ('dbo.people', 'U') IS NOT NULL
27
+ DROP TABLE people;
28
+ GO
29
+ CREATE TABLE people
30
+ (
31
+ name varchar(30),
32
+ age varchar(20),
33
+ CONSTRAINT pk_people PRIMARY KEY NONCLUSTERED (name, age)
34
+ );
35
+
36
+ INSERT products
37
+ (name, description)
38
+ VALUES
39
+ ('Bananas', 'Fruit thing');
40
+
41
+ INSERT products
42
+ (name, description)
43
+ VALUES
44
+ ('Meat', 'Animal thing');
45
+
46
+ INSERT tasks
47
+ (taskname, productid)
48
+ VALUES
49
+ ('Processing', 1);
50
+
51
+ INSERT people
52
+ (name, age)
53
+ VALUES
54
+ ('Bob', '30');
@@ -0,0 +1,12 @@
1
+ version: "3.8"
2
+ services:
3
+ # password: Passw0rd
4
+ # user: sa
5
+ # database: master
6
+ mssql:
7
+ image: bb/mssql
8
+ build:
9
+ context: .
10
+ dockerfile: data/Dockerfile
11
+ ports:
12
+ - "1433:1433"
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ docker-compose down
3
+ docker volume prune -f
@@ -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
@@ -44,6 +44,9 @@ const {
44
44
  revertClientLibrary,
45
45
  } = require("../../utilities/fileSystem/clientLibrary")
46
46
  const { getTenantId, isMultiTenant } = require("@budibase/auth/tenancy")
47
+ const { syncGlobalUsers } = require("./user")
48
+ const { app: appCache } = require("@budibase/auth/cache")
49
+ const { cleanupAutomations } = require("../../automations/utils")
47
50
 
48
51
  const URL_REGEX_SLASH = /\/|\\/g
49
52
 
@@ -197,7 +200,7 @@ exports.fetchAppPackage = async ctx => {
197
200
  application,
198
201
  screens,
199
202
  layouts,
200
- clientLibPath: clientLibraryPath(ctx.params.appId),
203
+ clientLibPath: clientLibraryPath(ctx.params.appId, application.version),
201
204
  }
202
205
  }
203
206
 
@@ -253,6 +256,7 @@ exports.create = async ctx => {
253
256
  await createApp(appId)
254
257
  }
255
258
 
259
+ await appCache.invalidateAppMetadata(appId, newApplication)
256
260
  ctx.status = 200
257
261
  ctx.body = newApplication
258
262
  }
@@ -316,8 +320,12 @@ exports.delete = async ctx => {
316
320
  if (!env.isTest() && !ctx.query.unpublish) {
317
321
  await deleteApp(ctx.params.appId)
318
322
  }
323
+ if (ctx.query && ctx.query.unpublish) {
324
+ await cleanupAutomations(ctx.params.appId)
325
+ }
319
326
  // make sure the app/role doesn't stick around after the app has been deleted
320
327
  await removeAppFromUserRoles(ctx, ctx.params.appId)
328
+ await appCache.invalidateAppMetadata(ctx.params.appId)
321
329
 
322
330
  ctx.status = 200
323
331
  ctx.body = result
@@ -328,6 +336,8 @@ exports.sync = async (ctx, next) => {
328
336
  if (!isDevAppID(appId)) {
329
337
  ctx.throw(400, "This action cannot be performed for production apps")
330
338
  }
339
+
340
+ // replicate prod to dev
331
341
  const prodAppId = getDeployedAppID(appId)
332
342
 
333
343
  try {
@@ -357,6 +367,10 @@ exports.sync = async (ctx, next) => {
357
367
  } catch (err) {
358
368
  error = err
359
369
  }
370
+
371
+ // sync the users
372
+ await syncGlobalUsers(appId)
373
+
360
374
  if (error) {
361
375
  ctx.throw(400, error)
362
376
  } else {
@@ -380,7 +394,10 @@ const updateAppPackage = async (ctx, appPackage, appId) => {
380
394
  // Redis, shouldn't ever store it
381
395
  delete newAppPackage.lockedBy
382
396
 
383
- 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
384
401
  }
385
402
 
386
403
  const createEmptyAppPackage = async (ctx, app) => {
@@ -14,6 +14,8 @@ exports.fetchSelf = async ctx => {
14
14
  }
15
15
 
16
16
  const user = await getFullUser(ctx, userId)
17
+ // this shouldn't be returned by the app self
18
+ delete user.roles
17
19
 
18
20
  if (appId) {
19
21
  const db = new CouchDB(appId)
@@ -36,6 +38,7 @@ exports.fetchSelf = async ctx => {
36
38
  // user has a role of some sort, return them
37
39
  else if (err.status === 404) {
38
40
  const metadata = {
41
+ ...user,
39
42
  _id: userId,
40
43
  }
41
44
  const dbResp = await db.put(metadata)
@@ -7,8 +7,9 @@ const {
7
7
  BudibaseInternalDB,
8
8
  getTableParams,
9
9
  } = require("../../db/utils")
10
+ const { BuildSchemaErrors } = require("../../constants")
10
11
  const { integrations } = require("../../integrations")
11
- const { makeExternalQuery } = require("./row/utils")
12
+ const { getDatasourceAndQuery } = require("./row/utils")
12
13
 
13
14
  exports.fetch = async function (ctx) {
14
15
  const database = new CouchDB(ctx.appId)
@@ -43,13 +44,17 @@ exports.buildSchemaFromDb = async function (ctx) {
43
44
  const db = new CouchDB(ctx.appId)
44
45
  const datasource = await db.get(ctx.params.datasourceId)
45
46
 
46
- const tables = await buildSchemaHelper(datasource)
47
+ const { tables, error } = await buildSchemaHelper(datasource)
47
48
  datasource.entities = tables
48
49
 
49
- const response = await db.put(datasource)
50
- datasource._rev = response.rev
50
+ const dbResp = await db.put(datasource)
51
+ datasource._rev = dbResp.rev
51
52
 
52
- ctx.body = datasource
53
+ const response = { datasource }
54
+ if (error) {
55
+ response.error = error
56
+ }
57
+ ctx.body = response
53
58
  }
54
59
 
55
60
  exports.update = async function (ctx) {
@@ -71,7 +76,7 @@ exports.update = async function (ctx) {
71
76
 
72
77
  ctx.status = 200
73
78
  ctx.message = "Datasource saved successfully."
74
- ctx.body = datasource
79
+ ctx.body = { datasource }
75
80
  }
76
81
 
77
82
  exports.save = async function (ctx) {
@@ -85,13 +90,15 @@ exports.save = async function (ctx) {
85
90
  ...ctx.request.body.datasource,
86
91
  }
87
92
 
93
+ let schemaError = null
88
94
  if (fetchSchema) {
89
- let tables = await buildSchemaHelper(datasource)
95
+ const { tables, error } = await buildSchemaHelper(datasource)
96
+ schemaError = error
90
97
  datasource.entities = tables
91
98
  }
92
99
 
93
- const response = await db.put(datasource)
94
- datasource._rev = response.rev
100
+ const dbResp = await db.put(datasource)
101
+ datasource._rev = dbResp.rev
95
102
 
96
103
  // Drain connection pools when configuration is changed
97
104
  if (datasource.source) {
@@ -101,17 +108,27 @@ exports.save = async function (ctx) {
101
108
  }
102
109
  }
103
110
 
104
- ctx.status = 200
105
- ctx.message = "Datasource saved successfully."
106
- ctx.body = datasource
111
+ const response = { datasource }
112
+ if (schemaError) {
113
+ response.error = schemaError
114
+ }
115
+ ctx.body = response
107
116
  }
108
117
 
109
118
  exports.destroy = async function (ctx) {
110
119
  const db = new CouchDB(ctx.appId)
111
120
 
112
121
  // Delete all queries for the datasource
113
- const rows = await db.allDocs(getQueryParams(ctx.params.datasourceId, null))
114
- 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
+ )
115
132
 
116
133
  // delete the datasource
117
134
  await db.remove(ctx.params.datasourceId, ctx.params.revId)
@@ -129,7 +146,7 @@ exports.find = async function (ctx) {
129
146
  exports.query = async function (ctx) {
130
147
  const queryJson = ctx.request.body
131
148
  try {
132
- ctx.body = await makeExternalQuery(ctx.appId, queryJson)
149
+ ctx.body = await getDatasourceAndQuery(ctx.appId, queryJson)
133
150
  } catch (err) {
134
151
  ctx.throw(400, err)
135
152
  }
@@ -143,5 +160,28 @@ const buildSchemaHelper = async datasource => {
143
160
  await connector.buildSchema(datasource._id, datasource.entities)
144
161
  datasource.entities = connector.tables
145
162
 
146
- return connector.tables
163
+ // make sure they all have a display name selected
164
+ for (let entity of Object.values(datasource.entities)) {
165
+ if (entity.primaryDisplay) {
166
+ continue
167
+ }
168
+ const notAutoColumn = Object.values(entity.schema).find(
169
+ schema => !schema.autocolumn
170
+ )
171
+ if (notAutoColumn) {
172
+ entity.primaryDisplay = notAutoColumn.name
173
+ }
174
+ }
175
+
176
+ const errors = connector.schemaErrors
177
+ let error = null
178
+ if (errors && Object.keys(errors).length > 0) {
179
+ const noKeyTables = Object.entries(errors)
180
+ .filter(entry => entry[1] === BuildSchemaErrors.NO_KEY)
181
+ .map(([name]) => name)
182
+ error = `No primary key constraint found for the following: ${noKeyTables.join(
183
+ ", "
184
+ )}`
185
+ }
186
+ return { tables: connector.tables, error }
147
187
  }
@@ -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
  }