@budibase/server 2.5.9 → 2.5.10-alpha.1

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 (198) hide show
  1. package/builder/assets/index.24635afb.js +1794 -0
  2. package/builder/assets/index.4eae16b2.css +6 -0
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/application.js +3 -4
  5. package/dist/api/controllers/automation.js +13 -7
  6. package/dist/api/controllers/datasource.js +1 -1
  7. package/dist/api/controllers/dev.js +1 -1
  8. package/dist/api/controllers/ops.js +40 -0
  9. package/dist/api/controllers/plugin/index.js +6 -37
  10. package/dist/api/controllers/query/index.js +2 -2
  11. package/dist/api/controllers/row/ExternalRequest.js +21 -14
  12. package/dist/api/controllers/row/internal.js +5 -2
  13. package/dist/api/controllers/row/utils.js +2 -2
  14. package/dist/api/controllers/table/index.js +2 -2
  15. package/dist/api/controllers/table/utils.js +9 -3
  16. package/dist/api/controllers/user.js +1 -83
  17. package/dist/api/controllers/view/exporters.js +3 -1
  18. package/dist/api/index.js +1 -2
  19. package/dist/api/routes/index.js +2 -2
  20. package/dist/api/routes/{cloud.js → ops.js} +19 -6
  21. package/dist/api/routes/user.js +0 -1
  22. package/dist/app.js +4 -13
  23. package/dist/automations/actions.js +32 -6
  24. package/dist/automations/index.js +3 -2
  25. package/dist/automations/steps/bash.js +6 -6
  26. package/dist/automations/steps/createRow.js +11 -11
  27. package/dist/automations/steps/delay.js +3 -3
  28. package/dist/automations/steps/deleteRow.js +8 -8
  29. package/dist/automations/steps/discord.js +8 -8
  30. package/dist/automations/steps/executeQuery.js +9 -9
  31. package/dist/automations/steps/executeScript.js +6 -6
  32. package/dist/automations/steps/filter.js +6 -6
  33. package/dist/automations/steps/integromat.js +10 -10
  34. package/dist/automations/steps/loop.js +9 -9
  35. package/dist/automations/steps/outgoingWebhook.js +10 -10
  36. package/dist/automations/steps/queryRows.js +14 -14
  37. package/dist/automations/steps/sendSmtpEmail.js +9 -9
  38. package/dist/automations/steps/serverLog.js +4 -4
  39. package/dist/automations/steps/slack.js +6 -6
  40. package/dist/automations/steps/updateRow.js +11 -11
  41. package/dist/automations/steps/zapier.js +9 -9
  42. package/dist/automations/triggerInfo/app.js +5 -5
  43. package/dist/automations/triggerInfo/cron.js +4 -4
  44. package/dist/automations/triggerInfo/rowDeleted.js +5 -5
  45. package/dist/automations/triggerInfo/rowSaved.js +7 -7
  46. package/dist/automations/triggerInfo/rowUpdated.js +7 -7
  47. package/dist/automations/triggerInfo/webhook.js +6 -6
  48. package/dist/db/utils.js +3 -2
  49. package/dist/environment.js +0 -1
  50. package/dist/events/docUpdates/index.js +17 -0
  51. package/dist/events/docUpdates/processors.js +18 -0
  52. package/dist/events/docUpdates/syncUsers.js +49 -0
  53. package/dist/events/index.js +3 -0
  54. package/dist/integrations/base/sqlTable.js +9 -2
  55. package/dist/integrations/index.js +3 -3
  56. package/dist/integrations/microsoftSqlServer.js +5 -2
  57. package/dist/integrations/mysql.js +5 -3
  58. package/dist/integrations/postgres.js +7 -5
  59. package/dist/integrations/redis.js +7 -0
  60. package/dist/integrations/rest.js +4 -0
  61. package/dist/migrations/functions/syncQuotas.js +2 -0
  62. package/dist/migrations/functions/usageQuotas/syncApps.js +1 -2
  63. package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
  64. package/dist/migrations/functions/usageQuotas/syncUsers.js +21 -0
  65. package/dist/sdk/app/applications/sync.js +117 -23
  66. package/dist/sdk/app/backups/exports.js +14 -38
  67. package/dist/sdk/index.js +2 -0
  68. package/dist/sdk/plugins/index.js +27 -0
  69. package/dist/sdk/plugins/plugins.js +53 -0
  70. package/dist/sdk/users/utils.js +21 -4
  71. package/dist/startup.js +31 -28
  72. package/dist/threads/automation.js +16 -5
  73. package/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/dist/utilities/csv.js +33 -0
  75. package/dist/utilities/fileSystem/plugin.js +33 -23
  76. package/dist/utilities/global.js +17 -12
  77. package/dist/utilities/rowProcessor/utils.js +4 -5
  78. package/dist/utilities/schema.js +5 -1
  79. package/dist/watch.js +2 -2
  80. package/dist/websockets/client.js +14 -0
  81. package/dist/websockets/grid.js +60 -0
  82. package/dist/websockets/index.js +17 -0
  83. package/dist/websockets/websocket.js +78 -0
  84. package/package.json +16 -16
  85. package/scripts/dev/manage.js +2 -0
  86. package/scripts/integrations/mssql/data/entrypoint.sh +1 -0
  87. package/scripts/integrations/mssql/data/setup.sql +17 -17
  88. package/scripts/integrations/mysql/init.sql +1 -1
  89. package/scripts/integrations/postgres/init.sql +1 -0
  90. package/src/api/controllers/application.ts +4 -4
  91. package/src/api/controllers/automation.ts +12 -6
  92. package/src/api/controllers/datasource.ts +15 -5
  93. package/src/api/controllers/dev.ts +2 -2
  94. package/src/api/controllers/ops.ts +32 -0
  95. package/src/api/controllers/plugin/index.ts +8 -45
  96. package/src/api/controllers/query/index.ts +2 -2
  97. package/src/api/controllers/row/ExternalRequest.ts +21 -12
  98. package/src/api/controllers/row/internal.ts +13 -11
  99. package/src/api/controllers/row/utils.ts +4 -4
  100. package/src/api/controllers/table/index.ts +2 -2
  101. package/src/api/controllers/table/utils.ts +10 -3
  102. package/src/api/controllers/user.ts +10 -96
  103. package/src/api/controllers/view/exporters.ts +3 -1
  104. package/src/api/index.ts +2 -4
  105. package/src/api/routes/index.ts +2 -2
  106. package/src/api/routes/ops.ts +30 -0
  107. package/src/api/routes/tests/automation.spec.js +7 -4
  108. package/src/api/routes/tests/user.spec.js +48 -37
  109. package/src/api/routes/user.ts +0 -5
  110. package/src/app.ts +4 -15
  111. package/src/automations/actions.ts +56 -24
  112. package/src/automations/index.ts +1 -1
  113. package/src/automations/steps/bash.ts +10 -7
  114. package/src/automations/steps/createRow.ts +15 -12
  115. package/src/automations/steps/delay.ts +6 -4
  116. package/src/automations/steps/deleteRow.ts +12 -9
  117. package/src/automations/steps/discord.ts +10 -8
  118. package/src/automations/steps/executeQuery.ts +13 -10
  119. package/src/automations/steps/executeScript.ts +10 -7
  120. package/src/automations/steps/filter.ts +8 -6
  121. package/src/automations/steps/integromat.ts +12 -10
  122. package/src/automations/steps/loop.ts +16 -10
  123. package/src/automations/steps/outgoingWebhook.ts +14 -11
  124. package/src/automations/steps/queryRows.ts +18 -15
  125. package/src/automations/steps/sendSmtpEmail.ts +11 -9
  126. package/src/automations/steps/serverLog.ts +6 -4
  127. package/src/automations/steps/slack.ts +8 -6
  128. package/src/automations/steps/updateRow.ts +15 -12
  129. package/src/automations/steps/zapier.ts +11 -9
  130. package/src/automations/tests/utilities/index.ts +2 -2
  131. package/src/automations/triggerInfo/app.ts +8 -5
  132. package/src/automations/triggerInfo/cron.ts +7 -4
  133. package/src/automations/triggerInfo/rowDeleted.ts +8 -5
  134. package/src/automations/triggerInfo/rowSaved.ts +10 -7
  135. package/src/automations/triggerInfo/rowUpdated.ts +10 -7
  136. package/src/automations/triggerInfo/webhook.ts +9 -6
  137. package/src/db/utils.ts +1 -0
  138. package/src/environment.ts +0 -1
  139. package/src/events/docUpdates/index.ts +1 -0
  140. package/src/events/docUpdates/processors.ts +14 -0
  141. package/src/events/docUpdates/syncUsers.ts +35 -0
  142. package/src/events/index.ts +1 -0
  143. package/src/integration-test/postgres.spec.ts +3 -1
  144. package/src/integrations/base/sqlTable.ts +9 -2
  145. package/src/integrations/index.ts +3 -3
  146. package/src/integrations/microsoftSqlServer.ts +5 -2
  147. package/src/integrations/mysql.ts +5 -3
  148. package/src/integrations/postgres.ts +7 -5
  149. package/src/integrations/redis.ts +8 -0
  150. package/src/integrations/rest.ts +3 -0
  151. package/src/migrations/functions/syncQuotas.ts +2 -0
  152. package/src/migrations/functions/usageQuotas/syncApps.ts +2 -3
  153. package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
  154. package/src/migrations/functions/usageQuotas/syncUsers.ts +9 -0
  155. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
  156. package/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts +26 -0
  157. package/src/migrations/index.ts +1 -0
  158. package/src/sdk/app/applications/sync.ts +129 -22
  159. package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
  160. package/src/sdk/app/backups/exports.ts +17 -41
  161. package/src/sdk/index.ts +2 -0
  162. package/src/sdk/plugins/index.ts +5 -0
  163. package/src/sdk/plugins/plugins.ts +41 -0
  164. package/src/sdk/users/tests/utils.spec.ts +1 -32
  165. package/src/sdk/users/utils.ts +23 -5
  166. package/src/startup.ts +36 -34
  167. package/src/tests/jestEnv.ts +0 -1
  168. package/src/tests/jestSetup.ts +0 -1
  169. package/src/tests/utilities/TestConfiguration.ts +28 -0
  170. package/src/tests/utilities/structures.ts +25 -17
  171. package/src/threads/automation.ts +18 -6
  172. package/src/utilities/csv.ts +22 -0
  173. package/src/utilities/fileSystem/plugin.ts +13 -4
  174. package/src/utilities/global.ts +21 -16
  175. package/src/utilities/rowProcessor/utils.ts +9 -10
  176. package/src/utilities/schema.ts +8 -0
  177. package/src/utilities/tests/csv.spec.ts +33 -0
  178. package/src/watch.ts +2 -2
  179. package/src/websockets/client.ts +11 -0
  180. package/src/websockets/grid.ts +55 -0
  181. package/src/websockets/index.ts +14 -0
  182. package/src/websockets/websocket.ts +83 -0
  183. package/tsconfig.build.json +3 -5
  184. package/tsconfig.json +2 -1
  185. package/builder/assets/index.0b358332.js +0 -1817
  186. package/builder/assets/index.7f9a008b.css +0 -6
  187. package/dist/api/controllers/cloud.js +0 -130
  188. package/dist/elasticApm.js +0 -14
  189. package/dist/package.json +0 -180
  190. package/dist/websocket.js +0 -22
  191. package/scripts/likeCypress.ts +0 -35
  192. package/src/api/controllers/cloud.ts +0 -119
  193. package/src/api/routes/cloud.ts +0 -18
  194. package/src/api/routes/tests/cloud.spec.ts +0 -54
  195. package/src/elasticApm.ts +0 -10
  196. package/src/migrations/functions/tests/syncQuotas.spec.js +0 -26
  197. package/src/tests/logging.ts +0 -34
  198. package/src/websocket.ts +0 -26
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const backend_core_1 = require("@budibase/backend-core");
13
+ const pro_1 = require("@budibase/pro");
14
+ const types_1 = require("@budibase/types");
15
+ const sync_1 = require("../../sdk/app/applications/sync");
16
+ function process(updateCb) {
17
+ const processor = (update) => __awaiter(this, void 0, void 0, function* () {
18
+ var _a;
19
+ try {
20
+ const docId = update.id;
21
+ const isGroup = docId.startsWith(backend_core_1.constants.DocumentType.GROUP);
22
+ let userIds;
23
+ if (isGroup) {
24
+ const group = yield pro_1.sdk.groups.get(docId);
25
+ userIds = ((_a = group.users) === null || _a === void 0 ? void 0 : _a.map(user => user._id)) || [];
26
+ }
27
+ else {
28
+ userIds = [docId];
29
+ }
30
+ if (userIds.length > 0) {
31
+ yield (0, sync_1.syncUsersToAllApps)(userIds);
32
+ }
33
+ if (updateCb) {
34
+ updateCb(docId);
35
+ }
36
+ }
37
+ catch (err) {
38
+ // if something not found - no changes to perform
39
+ if ((err === null || err === void 0 ? void 0 : err.status) === 404) {
40
+ return;
41
+ }
42
+ else {
43
+ backend_core_1.logging.logAlert("Failed to perform user/group app sync", err);
44
+ }
45
+ }
46
+ });
47
+ return { events: types_1.UserGroupSyncEvents, processor };
48
+ }
49
+ exports.default = process;
@@ -3,6 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.init = void 0;
6
7
  const BudibaseEmitter_1 = __importDefault(require("./BudibaseEmitter"));
7
8
  const emitter = new BudibaseEmitter_1.default();
9
+ var docUpdates_1 = require("./docUpdates");
10
+ Object.defineProperty(exports, "init", { enumerable: true, get: function () { return docUpdates_1.init; } });
8
11
  exports.default = emitter;
@@ -69,10 +69,17 @@ function generateSchema(schema, table, tables, oldTable = null, renamed) {
69
69
  if (!relatedTable) {
70
70
  throw "Referenced table doesn't exist";
71
71
  }
72
- schema.integer(column.foreignKey).unsigned();
72
+ const relatedPrimary = relatedTable.primary[0];
73
+ const externalType = relatedTable.schema[relatedPrimary].externalType;
74
+ if (externalType) {
75
+ schema.specificType(column.foreignKey, externalType);
76
+ }
77
+ else {
78
+ schema.integer(column.foreignKey).unsigned();
79
+ }
73
80
  schema
74
81
  .foreign(column.foreignKey)
75
- .references(`${tableName}.${relatedTable.primary[0]}`);
82
+ .references(`${tableName}.${relatedPrimary}`);
76
83
  }
77
84
  break;
78
85
  }
@@ -29,11 +29,11 @@ const firebase_1 = __importDefault(require("./firebase"));
29
29
  const redis_1 = __importDefault(require("./redis"));
30
30
  const snowflake_1 = __importDefault(require("./snowflake"));
31
31
  const oracle_1 = __importDefault(require("./oracle"));
32
- const plugin_1 = require("../api/controllers/plugin");
33
32
  const types_1 = require("@budibase/types");
34
33
  const fileSystem_1 = require("../utilities/fileSystem");
35
34
  const environment_1 = __importDefault(require("../environment"));
36
35
  const lodash_1 = require("lodash");
36
+ const sdk_1 = __importDefault(require("../sdk"));
37
37
  const DEFINITIONS = {
38
38
  [types_1.SourceName.POSTGRES]: postgres_1.default.schema,
39
39
  [types_1.SourceName.DYNAMODB]: dynamodb_1.default.schema,
@@ -91,7 +91,7 @@ function getDefinitions() {
91
91
  return __awaiter(this, void 0, void 0, function* () {
92
92
  const pluginSchemas = {};
93
93
  if (environment_1.default.SELF_HOSTED) {
94
- const plugins = yield (0, plugin_1.getPlugins)(types_1.PluginType.DATASOURCE);
94
+ const plugins = yield sdk_1.default.plugins.fetch(types_1.PluginType.DATASOURCE);
95
95
  // extract the actual schema from each custom
96
96
  for (let plugin of plugins) {
97
97
  const sourceId = plugin.name;
@@ -111,7 +111,7 @@ function getIntegration(integration) {
111
111
  return INTEGRATIONS[integration];
112
112
  }
113
113
  if (environment_1.default.SELF_HOSTED) {
114
- const plugins = yield (0, plugin_1.getPlugins)(types_1.PluginType.DATASOURCE);
114
+ const plugins = yield sdk_1.default.plugins.fetch(types_1.PluginType.DATASOURCE);
115
115
  for (let plugin of plugins) {
116
116
  if (plugin.name === integration) {
117
117
  // need to use commonJS require due to its dynamic runtime nature
@@ -206,8 +206,11 @@ class SqlServerIntegration extends sql_1.default {
206
206
  if (typeof name !== "string") {
207
207
  continue;
208
208
  }
209
- schema[name] = Object.assign(Object.assign({ autocolumn: !!autoColumns.find(col => col === name), name: name, constraints: {
210
- presence: requiredColumns.find(col => col === name),
209
+ const hasDefault = def.COLUMN_DEFAULT;
210
+ const isAuto = !!autoColumns.find(col => col === name);
211
+ const required = !!requiredColumns.find(col => col === name);
212
+ schema[name] = Object.assign(Object.assign({ autocolumn: isAuto, name: name, constraints: {
213
+ presence: required && !isAuto && !hasDefault,
211
214
  } }, (0, utils_1.convertSqlType)(def.DATA_TYPE)), { externalType: def.DATA_TYPE });
212
215
  }
213
216
  tables[tableName] = {
@@ -186,12 +186,14 @@ class MySQLIntegration extends sql_1.default {
186
186
  if (column.Key === "PRI" && primaryKeys.indexOf(column.Key) === -1) {
187
187
  primaryKeys.push(columnName);
188
188
  }
189
- const constraints = {
190
- presence: column.Null !== "YES",
191
- };
189
+ const hasDefault = column.Default != null;
192
190
  const isAuto = typeof column.Extra === "string" &&
193
191
  (column.Extra === "auto_increment" ||
194
192
  column.Extra.toLowerCase().includes("generated"));
193
+ const required = column.Null !== "YES";
194
+ const constraints = {
195
+ presence: required && !isAuto && !hasDefault,
196
+ };
195
197
  schema[columnName] = Object.assign(Object.assign({ name: columnName, autocolumn: isAuto, constraints }, (0, utils_1.convertSqlType)(column.Type)), { externalType: column.Type });
196
198
  }
197
199
  if (!tables[tableName]) {
@@ -227,13 +227,15 @@ class PostgresIntegration extends sql_1.default {
227
227
  const identity = !!(column.identity_generation ||
228
228
  column.identity_start ||
229
229
  column.identity_increment);
230
- const constraints = {
231
- presence: column.is_nullable === "NO",
232
- };
233
- const hasDefault = typeof column.column_default === "string" &&
230
+ const hasDefault = column.column_default != null;
231
+ const hasNextVal = typeof column.column_default === "string" &&
234
232
  column.column_default.startsWith("nextval");
235
233
  const isGenerated = column.is_generated && column.is_generated !== "NEVER";
236
- const isAuto = hasDefault || identity || isGenerated;
234
+ const isAuto = hasNextVal || identity || isGenerated;
235
+ const required = column.is_nullable === "NO";
236
+ const constraints = {
237
+ presence: required && !hasDefault && !isGenerated,
238
+ };
237
239
  tables[tableName].schema[columnName] = Object.assign(Object.assign({ autocolumn: isAuto, name: columnName, constraints }, (0, utils_1.convertSqlType)(column.data_type)), { externalType: column.data_type });
238
240
  }
239
241
  const final = (0, utils_1.finaliseExternalTables)(tables, entities);
@@ -38,6 +38,12 @@ const SCHEMA = {
38
38
  type: "password",
39
39
  required: false,
40
40
  },
41
+ db: {
42
+ type: "number",
43
+ required: false,
44
+ display: "DB",
45
+ default: 0,
46
+ },
41
47
  },
42
48
  query: {
43
49
  create: {
@@ -90,6 +96,7 @@ class RedisIntegration {
90
96
  port: this.config.port,
91
97
  username: this.config.username,
92
98
  password: this.config.password,
99
+ db: this.config.db,
93
100
  });
94
101
  }
95
102
  disconnect() {
@@ -166,6 +166,10 @@ class RestIntegration {
166
166
  }
167
167
  raw = rawXml;
168
168
  }
169
+ else if (contentType.includes("application/pdf")) {
170
+ data = yield response.arrayBuffer(); // Save PDF as ArrayBuffer
171
+ raw = Buffer.from(data);
172
+ }
169
173
  else {
170
174
  data = yield response.text();
171
175
  raw = data;
@@ -37,6 +37,7 @@ const usageQuotas_1 = require("./usageQuotas");
37
37
  const syncApps = __importStar(require("./usageQuotas/syncApps"));
38
38
  const syncRows = __importStar(require("./usageQuotas/syncRows"));
39
39
  const syncPlugins = __importStar(require("./usageQuotas/syncPlugins"));
40
+ const syncUsers = __importStar(require("./usageQuotas/syncUsers"));
40
41
  /**
41
42
  * Synchronise quotas to the state of the db.
42
43
  */
@@ -45,6 +46,7 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
45
46
  yield syncApps.run();
46
47
  yield syncRows.run();
47
48
  yield syncPlugins.run();
49
+ yield syncUsers.run();
48
50
  }));
49
51
  });
50
52
  exports.run = run;
@@ -18,8 +18,7 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
18
18
  const devApps = yield backend_core_1.db.getAllApps({ dev: true });
19
19
  const appCount = devApps ? devApps.length : 0;
20
20
  // sync app count
21
- const tenantId = backend_core_1.tenancy.getTenantId();
22
- console.log(`[Tenant: ${tenantId}] Syncing app count: ${appCount}`);
21
+ console.log(`Syncing app count: ${appCount}`);
23
22
  yield pro_1.quotas.setUsage(appCount, types_1.StaticQuotaName.APPS, types_1.QuotaUsageType.STATIC);
24
23
  });
25
24
  exports.run = run;
@@ -27,8 +27,7 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
27
27
  rowCount += rows.length;
28
28
  });
29
29
  // sync row count
30
- const tenantId = backend_core_1.tenancy.getTenantId();
31
- console.log(`[Tenant: ${tenantId}] Syncing row count: ${rowCount}`);
30
+ console.log(`Syncing row count: ${rowCount}`);
32
31
  yield pro_1.quotas.setUsagePerApp(counts, types_1.StaticQuotaName.ROWS, types_1.QuotaUsageType.STATIC);
33
32
  });
34
33
  exports.run = run;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.run = void 0;
13
+ const backend_core_1 = require("@budibase/backend-core");
14
+ const pro_1 = require("@budibase/pro");
15
+ const types_1 = require("@budibase/types");
16
+ const run = () => __awaiter(void 0, void 0, void 0, function* () {
17
+ const userCount = yield backend_core_1.users.getUserCount();
18
+ console.log(`Syncing user count: ${userCount}`);
19
+ yield pro_1.quotas.setUsage(userCount, types_1.StaticQuotaName.USERS, types_1.QuotaUsageType.STATIC);
20
+ });
21
+ exports.run = run;
@@ -12,10 +12,108 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.syncApp = void 0;
15
+ exports.syncApp = exports.syncUsersToAllApps = void 0;
16
16
  const environment_1 = __importDefault(require("../../../environment"));
17
17
  const backend_core_1 = require("@budibase/backend-core");
18
+ const pro_1 = require("@budibase/pro");
18
19
  const __1 = __importDefault(require("../../"));
20
+ const global_1 = require("../../../utilities/global");
21
+ const utils_1 = require("../../../db/utils");
22
+ function syncUsersToApp(appId, users, groups) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ if (!(yield backend_core_1.db.dbExists(appId))) {
25
+ return;
26
+ }
27
+ yield backend_core_1.context.doInAppContext(appId, () => __awaiter(this, void 0, void 0, function* () {
28
+ const db = backend_core_1.context.getAppDB();
29
+ for (let user of users) {
30
+ let ctxUser = user;
31
+ let deletedUser = false;
32
+ const metadataId = (0, utils_1.generateUserMetadataID)(user._id);
33
+ if (user.deleted) {
34
+ deletedUser = true;
35
+ }
36
+ // make sure role is correct
37
+ if (!deletedUser) {
38
+ ctxUser = yield (0, global_1.processUser)(ctxUser, { appId, groups });
39
+ }
40
+ let roleId = ctxUser.roleId;
41
+ if (roleId === backend_core_1.roles.BUILTIN_ROLE_IDS.PUBLIC) {
42
+ roleId = undefined;
43
+ }
44
+ let metadata;
45
+ try {
46
+ metadata = yield db.get(metadataId);
47
+ }
48
+ catch (err) {
49
+ if (err.status !== 404) {
50
+ throw err;
51
+ }
52
+ // no metadata and user is to be deleted, can skip
53
+ // no role - user isn't in app anyway
54
+ if (!roleId) {
55
+ continue;
56
+ }
57
+ else if (!deletedUser) {
58
+ // doesn't exist yet, creating it
59
+ metadata = {
60
+ tableId: utils_1.InternalTables.USER_METADATA,
61
+ };
62
+ }
63
+ }
64
+ // the user doesn't exist, or doesn't have a role anymore
65
+ // get rid of their metadata
66
+ if (deletedUser || !roleId) {
67
+ yield db.remove(metadata);
68
+ continue;
69
+ }
70
+ // assign the roleId for the metadata doc
71
+ if (roleId) {
72
+ metadata.roleId = roleId;
73
+ }
74
+ let combined = __1.default.users.combineMetadataAndUser(ctxUser, metadata);
75
+ // if no combined returned, there are no updates to make
76
+ if (combined) {
77
+ yield db.put(combined);
78
+ }
79
+ }
80
+ }));
81
+ });
82
+ }
83
+ function syncUsersToAllApps(userIds) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ // list of users, if one has been deleted it will be undefined in array
86
+ const users = (yield (0, global_1.getGlobalUsers)(userIds, {
87
+ noProcessing: true,
88
+ }));
89
+ const groups = yield pro_1.sdk.groups.fetch();
90
+ const finalUsers = [];
91
+ for (let userId of userIds) {
92
+ const user = users.find(user => user._id === userId);
93
+ if (!user) {
94
+ finalUsers.push({ _id: userId, deleted: true });
95
+ }
96
+ else {
97
+ finalUsers.push(user);
98
+ }
99
+ }
100
+ const devAppIds = yield backend_core_1.db.getDevAppIDs();
101
+ let promises = [];
102
+ for (let devAppId of devAppIds) {
103
+ const prodAppId = backend_core_1.db.getProdAppID(devAppId);
104
+ for (let appId of [prodAppId, devAppId]) {
105
+ promises.push(syncUsersToApp(appId, finalUsers, groups));
106
+ }
107
+ }
108
+ const resp = yield Promise.allSettled(promises);
109
+ const failed = resp.filter(promise => promise.status === "rejected");
110
+ if (failed.length > 0) {
111
+ const reasons = failed.map(fail => fail.reason);
112
+ backend_core_1.logging.logAlert("Failed to sync users to apps", reasons);
113
+ }
114
+ });
115
+ }
116
+ exports.syncUsersToAllApps = syncUsersToAllApps;
19
117
  function syncApp(appId, opts) {
20
118
  return __awaiter(this, void 0, void 0, function* () {
21
119
  if (environment_1.default.DISABLE_AUTO_PROD_APP_SYNC) {
@@ -31,31 +129,27 @@ function syncApp(appId, opts) {
31
129
  // specific case, want to make sure setup is skipped
32
130
  const prodDb = backend_core_1.context.getProdAppDB({ skip_setup: true });
33
131
  const exists = yield prodDb.exists();
34
- if (!exists) {
35
- // the database doesn't exist. Don't replicate
36
- return {
37
- message: "App sync not required, app not deployed.",
38
- };
39
- }
40
- const replication = new backend_core_1.db.Replication({
41
- source: prodAppId,
42
- target: appId,
43
- });
44
132
  let error;
45
- try {
46
- const replOpts = replication.appReplicateOpts();
47
- if (opts === null || opts === void 0 ? void 0 : opts.automationOnly) {
48
- replOpts.filter = (doc) => doc._id.startsWith(backend_core_1.db.DocumentType.AUTOMATION);
133
+ if (exists) {
134
+ const replication = new backend_core_1.db.Replication({
135
+ source: prodAppId,
136
+ target: appId,
137
+ });
138
+ try {
139
+ const replOpts = replication.appReplicateOpts();
140
+ if (opts === null || opts === void 0 ? void 0 : opts.automationOnly) {
141
+ replOpts.filter = (doc) => doc._id.startsWith(backend_core_1.db.DocumentType.AUTOMATION);
142
+ }
143
+ yield replication.replicate(replOpts);
144
+ }
145
+ catch (err) {
146
+ error = err;
147
+ }
148
+ finally {
149
+ yield replication.close();
49
150
  }
50
- yield replication.replicate(replOpts);
51
- }
52
- catch (err) {
53
- error = err;
54
- }
55
- finally {
56
- yield replication.close();
57
151
  }
58
- // sync the users
152
+ // sync the users - kept for safe keeping
59
153
  yield __1.default.users.syncGlobalUsers();
60
154
  if (error) {
61
155
  throw error;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.streamExportApp = exports.exportMultipleApps = exports.exportApp = exports.exportDB = void 0;
15
+ exports.streamExportApp = exports.exportApp = exports.exportDB = void 0;
16
16
  const backend_core_1 = require("@budibase/backend-core");
17
17
  const budibaseDir_1 = require("../../../utilities/budibaseDir");
18
18
  const fileSystem_1 = require("../../../utilities/fileSystem");
@@ -73,11 +73,14 @@ function exportDB(dbName, opts = {}) {
73
73
  });
74
74
  }
75
75
  exports.exportDB = exportDB;
76
- function defineFilter(excludeRows) {
76
+ function defineFilter(excludeRows, excludeLogs) {
77
77
  const ids = [utils_1.USER_METDATA_PREFIX, utils_1.LINK_USER_METADATA_PREFIX];
78
78
  if (excludeRows) {
79
79
  ids.push(utils_1.TABLE_ROW_PREFIX);
80
80
  }
81
+ if (excludeLogs) {
82
+ ids.push(utils_1.AUTOMATION_LOG_PREFIX);
83
+ }
81
84
  return (doc) => !ids.map(key => doc._id.includes(key)).reduce((prev, curr) => prev || curr);
82
85
  }
83
86
  /**
@@ -119,7 +122,10 @@ function exportApp(appId, config) {
119
122
  }
120
123
  // enforce an export of app DB to the tmp path
121
124
  const dbPath = (0, path_1.join)(tmpPath, constants_2.DB_EXPORT_FILE);
122
- yield exportDB(appId, Object.assign(Object.assign({}, config), { filter: defineFilter(config === null || config === void 0 ? void 0 : config.excludeRows), exportPath: dbPath }));
125
+ yield exportDB(appId, {
126
+ filter: defineFilter(config === null || config === void 0 ? void 0 : config.excludeRows, config === null || config === void 0 ? void 0 : config.excludeLogs),
127
+ exportPath: dbPath,
128
+ });
123
129
  // if tar requested, return where the tarball is
124
130
  if (config === null || config === void 0 ? void 0 : config.tar) {
125
131
  // now the tmpPath contains both the DB export and attachments, tar this
@@ -135,40 +141,6 @@ function exportApp(appId, config) {
135
141
  });
136
142
  }
137
143
  exports.exportApp = exportApp;
138
- /**
139
- * Export all apps + global DB (if supplied) to a single tarball, this includes
140
- * the attachments for each app as well.
141
- * @param {object[]} appMetadata The IDs and names of apps to export.
142
- * @param {string} globalDbContents The contents of the global DB to export as well.
143
- * @return {string} The path to the tarball.
144
- */
145
- function exportMultipleApps(appMetadata, globalDbContents) {
146
- return __awaiter(this, void 0, void 0, function* () {
147
- const tmpPath = (0, path_1.join)((0, budibaseDir_1.budibaseTempDir)(), uuid());
148
- fs_1.default.mkdirSync(tmpPath);
149
- let exportPromises = [];
150
- // export each app to a directory, then move it into the complete export
151
- const exportAndMove = (appId, appName) => __awaiter(this, void 0, void 0, function* () {
152
- const path = yield exportApp(appId);
153
- yield fs_1.default.promises.rename(path, (0, path_1.join)(tmpPath, appName));
154
- });
155
- for (let metadata of appMetadata) {
156
- exportPromises.push(exportAndMove(metadata.appId, metadata.name));
157
- }
158
- // wait for all exports to finish
159
- yield Promise.all(exportPromises);
160
- // add the global DB contents
161
- if (globalDbContents) {
162
- fs_1.default.writeFileSync((0, path_1.join)(tmpPath, constants_2.GLOBAL_DB_EXPORT_FILE), globalDbContents);
163
- }
164
- const appNames = appMetadata.map(metadata => metadata.name);
165
- const tarPath = tarFilesToTmp(tmpPath, [...appNames, constants_2.GLOBAL_DB_EXPORT_FILE]);
166
- // clear up the tmp path now tarball generated
167
- fs_1.default.rmSync(tmpPath, { recursive: true, force: true });
168
- return tarPath;
169
- });
170
- }
171
- exports.exportMultipleApps = exportMultipleApps;
172
144
  /**
173
145
  * Streams a backup of the database state for an app
174
146
  * @param {string} appId The ID of the app which is to be backed up.
@@ -177,7 +149,11 @@ exports.exportMultipleApps = exportMultipleApps;
177
149
  */
178
150
  function streamExportApp(appId, excludeRows) {
179
151
  return __awaiter(this, void 0, void 0, function* () {
180
- const tmpPath = yield exportApp(appId, { excludeRows, tar: true });
152
+ const tmpPath = yield exportApp(appId, {
153
+ excludeRows,
154
+ excludeLogs: true,
155
+ tar: true,
156
+ });
181
157
  return (0, fileSystem_1.streamFile)(tmpPath);
182
158
  });
183
159
  }
package/dist/sdk/index.js CHANGED
@@ -11,6 +11,7 @@ const datasources_1 = __importDefault(require("./app/datasources"));
11
11
  const queries_1 = __importDefault(require("./app/queries"));
12
12
  const rows_1 = __importDefault(require("./app/rows"));
13
13
  const users_1 = __importDefault(require("./users"));
14
+ const plugins_1 = __importDefault(require("./plugins"));
14
15
  const sdk = {
15
16
  backups: backups_1.default,
16
17
  tables: tables_1.default,
@@ -20,6 +21,7 @@ const sdk = {
20
21
  users: users_1.default,
21
22
  datasources: datasources_1.default,
22
23
  queries: queries_1.default,
24
+ plugins: plugins_1.default,
23
25
  };
24
26
  // default export for TS
25
27
  exports.default = sdk;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const plugins = __importStar(require("./plugins"));
27
+ exports.default = Object.assign({}, plugins);
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.processUploaded = exports.fetch = void 0;
16
+ const types_1 = require("@budibase/types");
17
+ const backend_core_1 = require("@budibase/backend-core");
18
+ const file_1 = require("../../api/controllers/plugin/file");
19
+ const environment_1 = __importDefault(require("../../environment"));
20
+ const websockets_1 = require("../../websockets");
21
+ const pro_1 = require("@budibase/pro");
22
+ function fetch(type) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const db = backend_core_1.tenancy.getGlobalDB();
25
+ const response = yield db.allDocs(backend_core_1.db.getPluginParams(null, {
26
+ include_docs: true,
27
+ }));
28
+ let plugins = response.rows.map((row) => row.doc);
29
+ plugins = backend_core_1.objectStore.enrichPluginURLs(plugins);
30
+ if (type) {
31
+ return plugins.filter((plugin) => { var _a; return ((_a = plugin.schema) === null || _a === void 0 ? void 0 : _a.type) === type; });
32
+ }
33
+ else {
34
+ return plugins;
35
+ }
36
+ });
37
+ }
38
+ exports.fetch = fetch;
39
+ function processUploaded(plugin, source) {
40
+ var _a;
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ const { metadata, directory } = yield (0, file_1.fileUpload)(plugin);
43
+ backend_core_1.plugins.validate(metadata === null || metadata === void 0 ? void 0 : metadata.schema);
44
+ // Only allow components in cloud
45
+ if (!environment_1.default.SELF_HOSTED && ((_a = metadata === null || metadata === void 0 ? void 0 : metadata.schema) === null || _a === void 0 ? void 0 : _a.type) !== types_1.PluginType.COMPONENT) {
46
+ throw new Error("Only component plugins are supported outside of self-host");
47
+ }
48
+ const doc = yield pro_1.sdk.plugins.storePlugin(metadata, directory, source);
49
+ websockets_1.clientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash });
50
+ return doc;
51
+ });
52
+ }
53
+ exports.processUploaded = processUploaded;
@@ -34,6 +34,10 @@ function combineMetadataAndUser(user, metadata) {
34
34
  if (found) {
35
35
  newDoc._rev = found._rev;
36
36
  }
37
+ // clear fields that shouldn't be in metadata
38
+ delete newDoc.password;
39
+ delete newDoc.forceResetPassword;
40
+ delete newDoc.roles;
37
41
  if (found == null || !(0, lodash_1.isEqual)(newDoc, found)) {
38
42
  return Object.assign(Object.assign({}, found), newDoc);
39
43
  }
@@ -53,10 +57,9 @@ function syncGlobalUsers() {
53
57
  return __awaiter(this, void 0, void 0, function* () {
54
58
  // sync user metadata
55
59
  const db = backend_core_1.context.getAppDB();
56
- const [users, metadata] = yield Promise.all([
57
- (0, global_1.getGlobalUsers)(),
58
- rawUserMetadata(),
59
- ]);
60
+ const resp = yield Promise.all([(0, global_1.getGlobalUsers)(), rawUserMetadata()]);
61
+ const users = resp[0];
62
+ const metadata = resp[1];
60
63
  const toWrite = [];
61
64
  for (let user of users) {
62
65
  const combined = combineMetadataAndUser(user, metadata);
@@ -64,6 +67,20 @@ function syncGlobalUsers() {
64
67
  toWrite.push(combined);
65
68
  }
66
69
  }
70
+ let foundEmails = [];
71
+ for (let data of metadata) {
72
+ if (!data._id) {
73
+ continue;
74
+ }
75
+ const alreadyExisting = data.email && foundEmails.indexOf(data.email) !== -1;
76
+ const globalId = (0, utils_1.getGlobalIDFromUserMetadataID)(data._id);
77
+ if (!users.find(user => user._id === globalId) || alreadyExisting) {
78
+ toWrite.push(Object.assign(Object.assign({}, data), { _deleted: true }));
79
+ }
80
+ if (data.email) {
81
+ foundEmails.push(data.email);
82
+ }
83
+ }
67
84
  yield db.bulkDocs(toWrite);
68
85
  });
69
86
  }