@budibase/server 1.0.26 → 1.0.27-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 (258) hide show
  1. package/__mocks__/node-fetch.ts +21 -0
  2. package/builder/assets/bb-spaceship.8f6e81e1.svg +227 -0
  3. package/builder/assets/{index.4fb3f887.css → index.0dce895b.css} +1 -1
  4. package/builder/assets/index.b98dd7ca.js +1348 -0
  5. package/builder/assets/{vendor.470042a4.js → vendor.f9faf6ab.js} +88 -88
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +1364 -1121
  8. package/coverage/coverage-final.json +37 -36
  9. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/application.js.html +59 -59
  12. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/automation.js.html +22 -10
  14. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  17. package/coverage/lcov-report/api/controllers/datasource.js.html +170 -68
  18. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/index.html +39 -54
  21. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/query/index.html +126 -0
  26. package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +225 -114
  27. package/coverage/lcov-report/api/controllers/query/validation.js.html +206 -0
  28. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/index.html +22 -22
  32. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/row/internal.js.html +38 -11
  34. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +7 -4
  35. package/coverage/lcov-report/api/controllers/row/utils.js.html +29 -20
  36. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +108 -9
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +18 -6
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +5 -5
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/index.html +9 -9
  66. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +19 -85
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +32 -2
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +1 -1
  84. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  85. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  86. package/coverage/lcov-report/automations/index.html +20 -20
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +31 -7
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/index.html +11 -11
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +5 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  114. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  115. package/coverage/lcov-report/automations/utils.js.html +48 -15
  116. package/coverage/lcov-report/constants/index.html +1 -1
  117. package/coverage/lcov-report/constants/index.js.html +22 -22
  118. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  119. package/coverage/lcov-report/constants/screens.js.html +1 -1
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  125. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +107 -80
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +1 -1
  133. package/coverage/lcov-report/events/utils.js.html +1 -1
  134. package/coverage/lcov-report/index.html +99 -84
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +10 -10
  139. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  140. package/coverage/lcov-report/middleware/currentapp.js.html +28 -28
  141. package/coverage/lcov-report/middleware/index.html +1 -1
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +11 -11
  143. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  146. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +31 -31
  149. package/coverage/lcov-report/threads/index.js.html +12 -12
  150. package/coverage/lcov-report/threads/query.js.html +396 -69
  151. package/coverage/lcov-report/threads/utils.js.html +358 -13
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  154. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  155. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  156. package/coverage/lcov-report/utilities/global.js.html +13 -13
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +69 -36
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +19 -19
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +235 -10
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  167. package/coverage/lcov-report/utilities/security.js.html +2 -2
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/users.js.html +1 -1
  170. package/coverage/lcov-report/utilities/workerRequests.js.html +19 -19
  171. package/coverage/lcov.info +2294 -1874
  172. package/dist/api/controllers/automation.js +7 -5
  173. package/dist/api/controllers/datasource.js +29 -0
  174. package/dist/api/controllers/query/import/index.js +79 -0
  175. package/dist/api/controllers/query/import/sources/base/index.js +64 -0
  176. package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
  177. package/dist/api/controllers/query/import/sources/curl.js +96 -0
  178. package/dist/api/controllers/query/import/sources/openapi2.js +142 -0
  179. package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  180. package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  181. package/dist/api/controllers/{query.js → query/index.js} +86 -52
  182. package/dist/api/controllers/query/validation.js +38 -0
  183. package/dist/api/controllers/row/internal.js +14 -6
  184. package/dist/api/controllers/row/internalSearch.js +2 -1
  185. package/dist/api/controllers/row/utils.js +13 -6
  186. package/dist/api/controllers/user.js +37 -1
  187. package/dist/api/controllers/webhook.js +4 -0
  188. package/dist/api/routes/query.js +5 -33
  189. package/dist/api/routes/user.js +3 -1
  190. package/dist/automations/steps/executeQuery.js +8 -1
  191. package/dist/automations/steps/outgoingWebhook.js +2 -3
  192. package/dist/automations/utils.js +10 -0
  193. package/dist/db/utils.js +8 -0
  194. package/dist/definitions/datasource.js +6 -1
  195. package/dist/integrations/base/sqlTable.js +1 -1
  196. package/dist/integrations/rest.js +207 -117
  197. package/dist/package.json +11 -4
  198. package/dist/tests/utilities/TestConfiguration.js +47 -0
  199. package/dist/threads/query.js +148 -40
  200. package/dist/threads/utils.js +105 -0
  201. package/dist/tsconfig.tsbuildinfo +1 -1
  202. package/dist/utilities/fileSystem/utilities.js +2 -1
  203. package/dist/utilities/index.js +10 -0
  204. package/dist/utilities/rowProcessor/index.js +76 -0
  205. package/package.json +12 -5
  206. package/src/api/controllers/automation.js +8 -4
  207. package/src/api/controllers/datasource.js +34 -0
  208. package/src/api/controllers/query/import/index.ts +85 -0
  209. package/src/api/controllers/query/import/sources/base/index.ts +87 -0
  210. package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
  211. package/src/api/controllers/query/import/sources/curl.ts +102 -0
  212. package/src/api/controllers/query/import/sources/openapi2.ts +163 -0
  213. package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +103 -0
  214. package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
  215. package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
  216. package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
  217. package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
  218. package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
  219. package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
  220. package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
  221. package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
  222. package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
  223. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  224. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
  225. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  226. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
  227. package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +238 -0
  228. package/src/api/controllers/query/import/tests/index.spec.js +109 -0
  229. package/src/api/controllers/query/index.js +195 -0
  230. package/src/api/controllers/query/validation.js +42 -0
  231. package/src/api/controllers/row/internal.js +14 -5
  232. package/src/api/controllers/row/internalSearch.js +2 -1
  233. package/src/api/controllers/row/utils.js +11 -8
  234. package/src/api/controllers/user.js +33 -0
  235. package/src/api/controllers/webhook.js +4 -0
  236. package/src/api/routes/query.js +13 -35
  237. package/src/api/routes/tests/datasource.spec.js +45 -0
  238. package/src/api/routes/tests/query.spec.js +69 -0
  239. package/src/api/routes/user.js +10 -0
  240. package/src/automations/steps/executeQuery.js +9 -1
  241. package/src/automations/steps/outgoingWebhook.js +2 -3
  242. package/src/automations/utils.js +11 -0
  243. package/src/db/utils.js +9 -0
  244. package/src/definitions/common.ts +2 -16
  245. package/src/definitions/datasource.ts +83 -1
  246. package/src/integrations/base/IntegrationBase.ts +4 -4
  247. package/src/integrations/base/sqlTable.ts +1 -1
  248. package/src/integrations/oracle.ts +1 -1
  249. package/src/integrations/rest.ts +230 -137
  250. package/src/integrations/tests/rest.spec.js +167 -19
  251. package/src/tests/utilities/TestConfiguration.js +57 -0
  252. package/src/threads/query.js +149 -40
  253. package/src/threads/utils.js +115 -0
  254. package/src/utilities/fileSystem/utilities.js +2 -0
  255. package/src/utilities/index.js +11 -0
  256. package/src/utilities/rowProcessor/index.js +75 -0
  257. package/builder/assets/index.8adef83f.js +0 -1316
  258. package/src/api/controllers/query.js +0 -158
@@ -8,11 +8,13 @@ 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 { processString } = require("@budibase/string-templates");
12
- const CouchDB = require("../../db");
13
- const { generateQueryID, getQueryParams, isProdAppID, } = require("../../db/utils");
14
- const { BaseQueryVerbs } = require("../../constants");
15
- const { Thread, ThreadType } = require("../../threads");
11
+ const CouchDB = require("../../../db");
12
+ const { generateQueryID, getQueryParams, isProdAppID, } = require("../../../db/utils");
13
+ const { BaseQueryVerbs } = require("../../../constants");
14
+ const { Thread, ThreadType } = require("../../../threads");
15
+ const { save: saveDatasource } = require("../datasource");
16
+ const { RestImporter } = require("./import");
17
+ const { invalidateDynamicVariables } = require("../../../threads/utils");
16
18
  const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 });
17
19
  // simple function to append "readable" to all read queries
18
20
  function enrichQueries(input) {
@@ -34,6 +36,38 @@ exports.fetch = function (ctx) {
34
36
  ctx.body = enrichQueries(body.rows.map(row => row.doc));
35
37
  });
36
38
  };
39
+ exports.import = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
40
+ const body = ctx.request.body;
41
+ const data = body.data;
42
+ const importer = new RestImporter(data);
43
+ yield importer.init();
44
+ let datasourceId;
45
+ if (!body.datasourceId) {
46
+ // construct new datasource
47
+ const info = yield importer.getInfo();
48
+ let datasource = {
49
+ type: "datasource",
50
+ source: "REST",
51
+ config: {
52
+ url: info.url,
53
+ defaultHeaders: [],
54
+ },
55
+ name: info.name,
56
+ };
57
+ // save the datasource
58
+ const datasourceCtx = Object.assign({}, ctx);
59
+ datasourceCtx.request.body.datasource = datasource;
60
+ yield saveDatasource(datasourceCtx);
61
+ datasourceId = datasourceCtx.body.datasource._id;
62
+ }
63
+ else {
64
+ // use existing datasource
65
+ datasourceId = body.datasourceId;
66
+ }
67
+ const importResult = yield importer.importQueries(ctx.appId, datasourceId);
68
+ ctx.body = Object.assign(Object.assign({}, importResult), { datasourceId });
69
+ ctx.status = 200;
70
+ });
37
71
  exports.save = function (ctx) {
38
72
  return __awaiter(this, void 0, void 0, function* () {
39
73
  const db = new CouchDB(ctx.appId);
@@ -47,44 +81,6 @@ exports.save = function (ctx) {
47
81
  ctx.message = `Query ${query.name} saved successfully.`;
48
82
  });
49
83
  };
50
- function enrichQueryFields(fields, parameters = {}) {
51
- return __awaiter(this, void 0, void 0, function* () {
52
- const enrichedQuery = {};
53
- // enrich the fields with dynamic parameters
54
- for (let key of Object.keys(fields)) {
55
- if (fields[key] == null) {
56
- continue;
57
- }
58
- if (typeof fields[key] === "object") {
59
- // enrich nested fields object
60
- enrichedQuery[key] = yield enrichQueryFields(fields[key], parameters);
61
- }
62
- else if (typeof fields[key] === "string") {
63
- // enrich string value as normal
64
- enrichedQuery[key] = yield processString(fields[key], parameters, {
65
- noHelpers: true,
66
- });
67
- }
68
- else {
69
- enrichedQuery[key] = fields[key];
70
- }
71
- }
72
- if (enrichedQuery.json ||
73
- enrichedQuery.customData ||
74
- enrichedQuery.requestBody) {
75
- try {
76
- enrichedQuery.json = JSON.parse(enrichedQuery.json ||
77
- enrichedQuery.customData ||
78
- enrichedQuery.requestBody);
79
- }
80
- catch (err) {
81
- throw { message: `JSON Invalid - error: ${err}` };
82
- }
83
- delete enrichedQuery.customData;
84
- }
85
- return enrichedQuery;
86
- });
87
- }
88
84
  exports.find = function (ctx) {
89
85
  return __awaiter(this, void 0, void 0, function* () {
90
86
  const db = new CouchDB(ctx.appId);
@@ -101,18 +97,24 @@ exports.preview = function (ctx) {
101
97
  return __awaiter(this, void 0, void 0, function* () {
102
98
  const db = new CouchDB(ctx.appId);
103
99
  const datasource = yield db.get(ctx.request.body.datasourceId);
104
- const { fields, parameters, queryVerb, transformer } = ctx.request.body;
105
- const enrichedQuery = yield enrichQueryFields(fields, parameters);
100
+ // preview may not have a queryId as it hasn't been saved, but if it does
101
+ // this stops dynamic variables from calling the same query
102
+ const { fields, parameters, queryVerb, transformer, queryId } = ctx.request.body;
106
103
  try {
107
- const { rows, keys } = yield Runner.run({
104
+ const { rows, keys, info, extra } = yield Runner.run({
105
+ appId: ctx.appId,
108
106
  datasource,
109
107
  queryVerb,
110
- query: enrichedQuery,
108
+ fields,
109
+ parameters,
111
110
  transformer,
111
+ queryId,
112
112
  });
113
113
  ctx.body = {
114
114
  rows,
115
115
  schemaFields: [...new Set(keys)],
116
+ info,
117
+ extra,
116
118
  };
117
119
  }
118
120
  catch (err) {
@@ -120,30 +122,62 @@ exports.preview = function (ctx) {
120
122
  }
121
123
  });
122
124
  };
123
- exports.execute = function (ctx) {
125
+ function execute(ctx, opts = { rowsOnly: false }) {
124
126
  return __awaiter(this, void 0, void 0, function* () {
125
127
  const db = new CouchDB(ctx.appId);
126
128
  const query = yield db.get(ctx.params.queryId);
127
129
  const datasource = yield db.get(query.datasourceId);
128
- const enrichedQuery = yield enrichQueryFields(query.fields, ctx.request.body.parameters);
129
130
  // call the relevant CRUD method on the integration class
130
131
  try {
131
- const { rows } = yield Runner.run({
132
+ const { rows, extra } = yield Runner.run({
133
+ appId: ctx.appId,
132
134
  datasource,
133
135
  queryVerb: query.queryVerb,
134
- query: enrichedQuery,
136
+ fields: query.fields,
137
+ parameters: ctx.request.body.parameters,
135
138
  transformer: query.transformer,
139
+ queryId: ctx.params.queryId,
136
140
  });
137
- ctx.body = rows;
141
+ if (opts && opts.rowsOnly) {
142
+ ctx.body = rows;
143
+ }
144
+ else {
145
+ ctx.body = Object.assign({ data: rows }, extra);
146
+ }
138
147
  }
139
148
  catch (err) {
140
149
  ctx.throw(400, err);
141
150
  }
142
151
  });
152
+ }
153
+ exports.executeV1 = function (ctx) {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ return execute(ctx, { rowsOnly: true });
156
+ });
157
+ };
158
+ exports.executeV2 = function (ctx) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ return execute(ctx, { rowsOnly: false });
161
+ });
143
162
  };
163
+ const removeDynamicVariables = (db, queryId) => __awaiter(void 0, void 0, void 0, function* () {
164
+ const query = yield db.get(queryId);
165
+ const datasource = yield db.get(query.datasourceId);
166
+ const dynamicVariables = datasource.config.dynamicVariables;
167
+ if (dynamicVariables) {
168
+ // delete dynamic variables from the datasource
169
+ const newVariables = dynamicVariables.filter(dv => dv.queryId !== queryId);
170
+ datasource.config.dynamicVariables = newVariables;
171
+ yield db.put(datasource);
172
+ // invalidate the deleted variables
173
+ const variablesToDelete = dynamicVariables.filter(dv => dv.queryId === queryId);
174
+ yield invalidateDynamicVariables(variablesToDelete);
175
+ }
176
+ });
144
177
  exports.destroy = function (ctx) {
145
178
  return __awaiter(this, void 0, void 0, function* () {
146
179
  const db = new CouchDB(ctx.appId);
180
+ yield removeDynamicVariables(db, ctx.params.queryId);
147
181
  yield db.remove(ctx.params.queryId, ctx.params.revId);
148
182
  ctx.message = `Query deleted.`;
149
183
  ctx.status = 200;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ const joiValidator = require("../../../middleware/joi-validator");
3
+ const Joi = require("joi");
4
+ exports.queryValidation = () => {
5
+ return Joi.object({
6
+ _id: Joi.string(),
7
+ _rev: Joi.string(),
8
+ name: Joi.string().required(),
9
+ fields: Joi.object().required(),
10
+ datasourceId: Joi.string().required(),
11
+ readable: Joi.boolean(),
12
+ parameters: Joi.array().items(Joi.object({
13
+ name: Joi.string(),
14
+ default: Joi.string().allow(""),
15
+ })),
16
+ queryVerb: Joi.string().allow().required(),
17
+ extra: Joi.object().optional(),
18
+ schema: Joi.object({}).required().unknown(true),
19
+ transformer: Joi.string().optional(),
20
+ flags: Joi.object().optional(),
21
+ });
22
+ };
23
+ exports.generateQueryValidation = () => {
24
+ // prettier-ignore
25
+ return joiValidator.body(exports.queryValidation());
26
+ };
27
+ exports.generateQueryPreviewValidation = () => {
28
+ // prettier-ignore
29
+ return joiValidator.body(Joi.object({
30
+ fields: Joi.object().required(),
31
+ queryVerb: Joi.string().allow().required(),
32
+ extra: Joi.object().optional(),
33
+ datasourceId: Joi.string().required(),
34
+ transformer: Joi.string().optional(),
35
+ parameters: Joi.object({}).required().unknown(true),
36
+ queryId: Joi.string().optional(),
37
+ }));
38
+ };
@@ -23,7 +23,7 @@ const CouchDB = require("../../../db");
23
23
  const linkRows = require("../../../db/linkedRows");
24
24
  const { getRowParams, generateRowID, DocumentTypes, InternalTables, } = require("../../../db/utils");
25
25
  const userController = require("../user");
26
- const { inputProcessing, outputProcessing, processAutoColumn, } = require("../../../utilities/rowProcessor");
26
+ const { inputProcessing, outputProcessing, processAutoColumn, cleanupAttachments, } = require("../../../utilities/rowProcessor");
27
27
  const { FieldTypes } = require("../../../constants");
28
28
  const { isEqual } = require("lodash");
29
29
  const { validate, findRow } = require("./utils");
@@ -32,6 +32,7 @@ const { getGlobalUsersFromMetadata } = require("../../../utilities/global");
32
32
  const inMemoryViews = require("../../../db/inMemoryView");
33
33
  const env = require("../../../environment");
34
34
  const { migrateToInMemoryView, migrateToDesignView, getFromDesignDoc, getFromMemoryDoc, } = require("../view/utils");
35
+ const { cloneDeep } = require("lodash/fp");
35
36
  const CALCULATION_TYPES = {
36
37
  SUM: "sum",
37
38
  COUNT: "count",
@@ -119,15 +120,15 @@ exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
119
120
  const inputs = ctx.request.body;
120
121
  const tableId = inputs.tableId;
121
122
  const isUserTable = tableId === InternalTables.USER_METADATA;
122
- let dbRow;
123
+ let oldRow;
123
124
  try {
124
- dbRow = yield db.get(inputs._id);
125
+ oldRow = yield db.get(inputs._id);
125
126
  }
126
127
  catch (err) {
127
128
  if (isUserTable) {
128
129
  // don't include the rev, it'll be the global rev
129
130
  // this time
130
- dbRow = {
131
+ oldRow = {
131
132
  _id: inputs._id,
132
133
  };
133
134
  }
@@ -137,13 +138,14 @@ exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
137
138
  }
138
139
  let dbTable = yield db.get(tableId);
139
140
  // need to build up full patch fields before coerce
141
+ let combinedRow = cloneDeep(oldRow);
140
142
  for (let key of Object.keys(inputs)) {
141
143
  if (!dbTable.schema[key])
142
144
  continue;
143
- dbRow[key] = inputs[key];
145
+ combinedRow[key] = inputs[key];
144
146
  }
145
147
  // this returns the table and row incase they have been updated
146
- let { table, row } = inputProcessing(ctx.user, dbTable, dbRow);
148
+ let { table, row } = inputProcessing(ctx.user, dbTable, combinedRow);
147
149
  const validateResult = yield validate({
148
150
  row,
149
151
  table,
@@ -159,6 +161,8 @@ exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
159
161
  tableId: row.tableId,
160
162
  table,
161
163
  });
164
+ // check if any attachments removed
165
+ yield cleanupAttachments(appId, table, { oldRow, row });
162
166
  if (isUserTable) {
163
167
  // the row has been updated, need to put it into the ctx
164
168
  ctx.request.body = row;
@@ -284,6 +288,8 @@ exports.destroy = function (ctx) {
284
288
  row,
285
289
  tableId: row.tableId,
286
290
  });
291
+ // remove any attachments that were on the row from object storage
292
+ yield cleanupAttachments(appId, table, { row });
287
293
  let response;
288
294
  if (ctx.params.tableId === InternalTables.USER_METADATA) {
289
295
  ctx.params = {
@@ -325,6 +331,8 @@ exports.bulkDestroy = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
325
331
  else {
326
332
  yield db.bulkDocs(rows.map(row => (Object.assign(Object.assign({}, row), { _deleted: true }))));
327
333
  }
334
+ // remove any attachments that were on the rows from object storage
335
+ yield cleanupAttachments(appId, table, { rows });
328
336
  yield Promise.all(updates);
329
337
  return { response: { ok: true }, rows };
330
338
  });
@@ -172,7 +172,8 @@ class QueryBuilder {
172
172
  }
173
173
  if (this.query.equal) {
174
174
  build(this.query.equal, (key, value) => {
175
- if (!value) {
175
+ // 0 evaluates to false, which means we would return all rows if we don't check it
176
+ if (!value && value !== 0) {
176
177
  return null;
177
178
  }
178
179
  return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`;
@@ -57,24 +57,31 @@ exports.validate = ({ appId, tableId, row, table }) => __awaiter(void 0, void 0,
57
57
  const errors = {};
58
58
  for (let fieldName of Object.keys(table.schema)) {
59
59
  const constraints = cloneDeep(table.schema[fieldName].constraints);
60
+ const type = table.schema[fieldName].type;
60
61
  // special case for options, need to always allow unselected (null)
61
- if (table.schema[fieldName].type ===
62
- (FieldTypes.OPTIONS || FieldTypes.ARRAY) &&
62
+ if ((type === FieldTypes.OPTIONS || type === FieldTypes.ARRAY) &&
63
63
  constraints.inclusion) {
64
64
  constraints.inclusion.push(null);
65
65
  }
66
66
  let res;
67
67
  // Validate.js doesn't seem to handle array
68
- if (table.schema[fieldName].type === FieldTypes.ARRAY &&
69
- row[fieldName] &&
70
- row[fieldName].length) {
68
+ if (type === FieldTypes.ARRAY && row[fieldName] && row[fieldName].length) {
71
69
  row[fieldName].map(val => {
72
70
  if (!constraints.inclusion.includes(val)) {
73
71
  errors[fieldName] = "Field not in list";
74
72
  }
75
73
  });
76
74
  }
77
- else if (table.schema[fieldName].type === FieldTypes.FORMULA) {
75
+ else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
76
+ // this should only happen if there is an error
77
+ try {
78
+ JSON.parse(row[fieldName]);
79
+ }
80
+ catch (err) {
81
+ errors[fieldName] = [`Contains invalid JSON`];
82
+ }
83
+ }
84
+ else if (type === FieldTypes.FORMULA) {
78
85
  res = validateJs.single(processStringSync(table.schema[fieldName].formula, row), constraints);
79
86
  }
80
87
  else {
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  const CouchDB = require("../../db");
12
- const { generateUserMetadataID, getUserMetadataParams, } = require("../../db/utils");
12
+ const { generateUserMetadataID, getUserMetadataParams, generateUserFlagID, } = require("../../db/utils");
13
13
  const { InternalTables } = require("../../db/utils");
14
14
  const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global");
15
15
  const { getFullUser } = require("../../utilities/users");
@@ -189,3 +189,39 @@ exports.findMetadata = function (ctx) {
189
189
  ctx.body = yield getFullUser(ctx, ctx.params.id);
190
190
  });
191
191
  };
192
+ exports.setFlag = function (ctx) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ const userId = ctx.user._id;
195
+ const { flag, value } = ctx.request.body;
196
+ if (!flag) {
197
+ ctx.throw(400, "Must supply a 'flag' field in request body.");
198
+ }
199
+ const flagDocId = generateUserFlagID(userId);
200
+ const db = new CouchDB(ctx.appId);
201
+ let doc;
202
+ try {
203
+ doc = yield db.get(flagDocId);
204
+ }
205
+ catch (err) {
206
+ doc = { _id: flagDocId };
207
+ }
208
+ doc[flag] = value || true;
209
+ yield db.put(doc);
210
+ ctx.body = { message: "Flag set successfully" };
211
+ });
212
+ };
213
+ exports.getFlags = function (ctx) {
214
+ return __awaiter(this, void 0, void 0, function* () {
215
+ const userId = ctx.user._id;
216
+ const docId = generateUserFlagID(userId);
217
+ const db = new CouchDB(ctx.appId);
218
+ let doc;
219
+ try {
220
+ doc = yield db.get(docId);
221
+ }
222
+ catch (err) {
223
+ doc = { _id: docId };
224
+ }
225
+ ctx.body = doc;
226
+ });
227
+ };
@@ -65,6 +65,10 @@ exports.buildSchema = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
65
65
  let automation = yield db.get(webhook.action.target);
66
66
  const autoOutputs = automation.definition.trigger.schema.outputs;
67
67
  let properties = webhook.bodySchema.properties;
68
+ // reset webhook outputs
69
+ autoOutputs.properties = {
70
+ body: autoOutputs.properties.body,
71
+ };
68
72
  for (let prop of Object.keys(properties)) {
69
73
  autoOutputs.properties[prop] = {
70
74
  type: properties[prop].type,
@@ -2,46 +2,18 @@
2
2
  const Router = require("@koa/router");
3
3
  const queryController = require("../controllers/query");
4
4
  const authorized = require("../../middleware/authorized");
5
- const Joi = require("joi");
6
5
  const { PermissionLevels, PermissionTypes, BUILDER, } = require("@budibase/auth/permissions");
7
- const joiValidator = require("../../middleware/joi-validator");
8
6
  const { bodyResource, bodySubResource, paramResource, } = require("../../middleware/resourceId");
7
+ const { generateQueryPreviewValidation, generateQueryValidation, } = require("../controllers/query/validation");
9
8
  const router = Router();
10
- function generateQueryValidation() {
11
- // prettier-ignore
12
- return joiValidator.body(Joi.object({
13
- _id: Joi.string(),
14
- _rev: Joi.string(),
15
- name: Joi.string().required(),
16
- fields: Joi.object().required(),
17
- datasourceId: Joi.string().required(),
18
- readable: Joi.boolean(),
19
- parameters: Joi.array().items(Joi.object({
20
- name: Joi.string(),
21
- default: Joi.string().allow(""),
22
- })),
23
- queryVerb: Joi.string().allow().required(),
24
- extra: Joi.object().optional(),
25
- schema: Joi.object({}).required().unknown(true),
26
- transformer: Joi.string().optional(),
27
- }));
28
- }
29
- function generateQueryPreviewValidation() {
30
- // prettier-ignore
31
- return joiValidator.body(Joi.object({
32
- fields: Joi.object().required(),
33
- queryVerb: Joi.string().allow().required(),
34
- extra: Joi.object().optional(),
35
- datasourceId: Joi.string().required(),
36
- transformer: Joi.string().optional(),
37
- parameters: Joi.object({}).required().unknown(true)
38
- }));
39
- }
40
9
  router
41
10
  .get("/api/queries", authorized(BUILDER), queryController.fetch)
42
11
  .post("/api/queries", bodySubResource("datasourceId", "_id"), authorized(BUILDER), generateQueryValidation(), queryController.save)
12
+ .post("/api/queries/import", authorized(BUILDER), queryController.import)
43
13
  .post("/api/queries/preview", bodyResource("datasourceId"), authorized(BUILDER), generateQueryPreviewValidation(), queryController.preview)
44
14
  .get("/api/queries/:queryId", paramResource("queryId"), authorized(PermissionTypes.QUERY, PermissionLevels.READ), queryController.find)
45
- .post("/api/queries/:queryId", paramResource("queryId"), authorized(PermissionTypes.QUERY, PermissionLevels.WRITE), queryController.execute)
15
+ // DEPRECATED - use new query endpoint for future work
16
+ .post("/api/queries/:queryId", paramResource("queryId"), authorized(PermissionTypes.QUERY, PermissionLevels.WRITE), queryController.executeV1)
17
+ .post("/api/v2/queries/:queryId", paramResource("queryId"), authorized(PermissionTypes.QUERY, PermissionLevels.WRITE), queryController.executeV2)
46
18
  .delete("/api/queries/:queryId/:revId", paramResource("queryId"), authorized(BUILDER), queryController.destroy);
47
19
  module.exports = router;
@@ -10,5 +10,7 @@ router
10
10
  .put("/api/users/metadata", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.updateMetadata)
11
11
  .post("/api/users/metadata/self", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.updateSelfMetadata)
12
12
  .delete("/api/users/metadata/:id", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.destroyMetadata)
13
- .post("/api/users/metadata/sync/:id", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.syncUser);
13
+ .post("/api/users/metadata/sync/:id", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.syncUser)
14
+ .post("/api/users/flags", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.setFlag)
15
+ .get("/api/users/flags", authorized(PermissionTypes.USER, PermissionLevels.READ), controller.getFlags);
14
16
  module.exports = router;
@@ -55,6 +55,10 @@ exports.definition = {
55
55
  type: "object",
56
56
  description: "The response from the datasource execution",
57
57
  },
58
+ info: {
59
+ type: "object",
60
+ description: "Some query types may return extra data, like headers from a REST query",
61
+ },
58
62
  success: {
59
63
  type: "boolean",
60
64
  description: "Whether the action was successful",
@@ -85,14 +89,17 @@ exports.run = function ({ inputs, appId, emitter }) {
85
89
  });
86
90
  try {
87
91
  yield queryController.execute(ctx);
92
+ const _b = ctx.body, { data } = _b, rest = __rest(_b, ["data"]);
88
93
  return {
89
- response: ctx.body,
94
+ response: data,
95
+ info: rest,
90
96
  success: true,
91
97
  };
92
98
  }
93
99
  catch (err) {
94
100
  return {
95
101
  success: false,
102
+ info: {},
96
103
  response: automationUtils.getError(err),
97
104
  };
98
105
  }
@@ -20,11 +20,10 @@ const RequestType = {
20
20
  };
21
21
  const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH];
22
22
  /**
23
- * Note, there is some functionality in this that is not currently exposed as it
24
- * is complex and maybe better to be opinionated here.
25
- * GET/DELETE requests cannot handle body elements so they will not be sent if configured.
23
+ * NOTE: this functionality is deprecated - it no longer should be used.
26
24
  */
27
25
  exports.definition = {
26
+ deprecated: true,
28
27
  name: "Outgoing webhook",
29
28
  tagline: "Send a {{inputs.requestMethod}} request",
30
29
  icon: "Send",
@@ -17,6 +17,7 @@ const newid = require("../db/newid");
17
17
  const { updateEntityMetadata } = require("../utilities");
18
18
  const { MetadataTypes } = require("../constants");
19
19
  const { getDeployedAppID } = require("@budibase/auth/db");
20
+ const { cloneDeep } = require("lodash/fp");
20
21
  const WH_STEP_ID = definitions.WEBHOOK.stepId;
21
22
  const CRON_STEP_ID = definitions.CRON.stepId;
22
23
  const Runner = new Thread(ThreadType.AUTOMATION);
@@ -43,6 +44,15 @@ exports.updateTestHistory = (appId, automation, history) => __awaiter(void 0, vo
43
44
  return metadata;
44
45
  });
45
46
  });
47
+ exports.removeDeprecated = definitions => {
48
+ const base = cloneDeep(definitions);
49
+ for (let key of Object.keys(base)) {
50
+ if (base[key].deprecated) {
51
+ delete base[key];
52
+ }
53
+ }
54
+ return base;
55
+ };
46
56
  // end the repetition and the job itself
47
57
  exports.disableAllCrons = (appId) => __awaiter(void 0, void 0, void 0, function* () {
48
58
  const promises = [];
package/dist/db/utils.js CHANGED
@@ -28,6 +28,7 @@ const DocumentTypes = {
28
28
  DEPLOYMENTS: "deployments",
29
29
  METADATA: "metadata",
30
30
  MEM_VIEW: "view",
31
+ USER_FLAG: "flag",
31
32
  };
32
33
  const ViewNames = {
33
34
  LINK: "by_link",
@@ -271,6 +272,13 @@ exports.getQueryParams = (datasourceId = null, otherProps = {}) => {
271
272
  }
272
273
  return getDocParams(DocumentTypes.QUERY, `${datasourceId}${SEPARATOR}`, otherProps);
273
274
  };
275
+ /**
276
+ * Generates a new flag document ID.
277
+ * @returns {string} The ID of the flag document that was generated.
278
+ */
279
+ exports.generateUserFlagID = userId => {
280
+ return `${DocumentTypes.USER_FLAG}${SEPARATOR}${userId}`;
281
+ };
274
282
  exports.generateMetadataID = (type, entityId) => {
275
283
  return `${DocumentTypes.METADATA}${SEPARATOR}${type}${SEPARATOR}${entityId}`;
276
284
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FilterTypes = exports.IncludeRelationships = exports.SourceNames = exports.DatasourceFieldTypes = exports.QueryTypes = exports.SortDirection = exports.Operation = void 0;
3
+ exports.AuthType = exports.FilterTypes = exports.IncludeRelationships = exports.SourceNames = exports.DatasourceFieldTypes = exports.QueryTypes = exports.SortDirection = exports.Operation = void 0;
4
4
  var Operation;
5
5
  (function (Operation) {
6
6
  Operation["CREATE"] = "CREATE";
@@ -66,3 +66,8 @@ var FilterTypes;
66
66
  FilterTypes["NOT_EMPTY"] = "notEmpty";
67
67
  FilterTypes["ONE_OF"] = "oneOf";
68
68
  })(FilterTypes = exports.FilterTypes || (exports.FilterTypes = {}));
69
+ var AuthType;
70
+ (function (AuthType) {
71
+ AuthType["BASIC"] = "basic";
72
+ AuthType["BEARER"] = "bearer";
73
+ })(AuthType = exports.AuthType || (exports.AuthType = {}));
@@ -29,7 +29,7 @@ function generateSchema(schema, table, tables, oldTable = null) {
29
29
  case FieldTypes.STRING:
30
30
  case FieldTypes.OPTIONS:
31
31
  case FieldTypes.LONGFORM:
32
- schema.string(key);
32
+ schema.text(key);
33
33
  break;
34
34
  case FieldTypes.NUMBER:
35
35
  // if meta is specified then this is a junction table entry