@budibase/server 1.0.46-alpha.2 → 1.0.46-alpha.6

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 (248) hide show
  1. package/builder/assets/{index.89280093.js → index.00221ff2.js} +244 -244
  2. package/builder/assets/{index.0df4f7ab.css → index.dd9e386f.css} +1 -1
  3. package/builder/assets/{vendor.10e2ad1b.js → vendor.3bd2f661.js} +1 -1
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +1802 -1639
  6. package/coverage/coverage-final.json +98 -94
  7. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/application.js.html +192 -129
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +72 -36
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +27 -42
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
  22. package/coverage/lcov-report/api/controllers/query/index.html +15 -15
  23. package/coverage/lcov-report/api/controllers/query/index.js.html +61 -28
  24. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  25. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
  28. package/coverage/lcov-report/api/controllers/row/index.html +5 -5
  29. package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
  30. package/coverage/lcov-report/api/controllers/row/internal.js.html +44 -44
  31. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +8 -8
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +29 -38
  33. package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
  34. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  35. package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
  36. package/coverage/lcov-report/api/controllers/table/index.html +16 -16
  37. package/coverage/lcov-report/api/controllers/table/index.js.html +25 -25
  38. package/coverage/lcov-report/api/controllers/table/internal.js.html +40 -34
  39. package/coverage/lcov-report/api/controllers/table/utils.js.html +76 -61
  40. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/user.js.html +20 -20
  42. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  43. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
  45. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  46. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  47. package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
  48. package/coverage/lcov-report/api/index.html +1 -1
  49. package/coverage/lcov-report/api/index.js.html +10 -10
  50. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/index.html +7 -22
  62. package/coverage/lcov-report/api/routes/index.js.html +4 -10
  63. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/static.js.html +17 -2
  74. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  79. package/coverage/lcov-report/automations/actions.js.html +24 -24
  80. package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
  81. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  82. package/coverage/lcov-report/automations/index.html +1 -1
  83. package/coverage/lcov-report/automations/index.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  85. package/coverage/lcov-report/automations/steps/createRow.js.html +13 -19
  86. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  87. package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
  88. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  89. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  90. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  91. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  92. package/coverage/lcov-report/automations/steps/index.html +13 -13
  93. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  94. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  95. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  96. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  97. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  99. package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
  100. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  101. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  102. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  103. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  104. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  106. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  109. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggers.js.html +18 -18
  111. package/coverage/lcov-report/automations/utils.js.html +32 -32
  112. package/coverage/lcov-report/constants/index.html +5 -5
  113. package/coverage/lcov-report/constants/index.js.html +36 -24
  114. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  115. package/coverage/lcov-report/constants/screens.js.html +4 -4
  116. package/coverage/lcov-report/db/client.js.html +18 -18
  117. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  118. package/coverage/lcov-report/db/index.html +15 -15
  119. package/coverage/lcov-report/db/index.js.html +3 -3
  120. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
  121. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  122. package/coverage/lcov-report/db/linkedRows/index.js.html +31 -31
  123. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
  124. package/coverage/lcov-report/db/newid.js.html +4 -4
  125. package/coverage/lcov-report/db/utils.js.html +85 -85
  126. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  127. package/coverage/lcov-report/events/index.html +1 -1
  128. package/coverage/lcov-report/events/index.js.html +5 -5
  129. package/coverage/lcov-report/events/utils.js.html +3 -3
  130. package/coverage/lcov-report/index.html +110 -80
  131. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  132. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  133. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  134. package/coverage/lcov-report/middleware/authorized.js.html +11 -11
  135. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  136. package/coverage/lcov-report/middleware/currentapp.js.html +34 -61
  137. package/coverage/lcov-report/middleware/index.html +25 -25
  138. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  139. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  140. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  141. package/coverage/lcov-report/middleware/usageQuota.js.html +275 -41
  142. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  143. package/coverage/lcov-report/migrations/usageQuotas/index.html +141 -0
  144. package/coverage/lcov-report/migrations/usageQuotas/index.js.html +152 -0
  145. package/coverage/lcov-report/{api/routes/hosting.js.html → migrations/usageQuotas/syncApps.js.html} +42 -27
  146. package/coverage/lcov-report/{api/controllers/hosting.js.html → migrations/usageQuotas/syncRows.js.html} +41 -44
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +15 -15
  149. package/coverage/lcov-report/threads/index.js.html +10 -10
  150. package/coverage/lcov-report/threads/query.js.html +23 -8
  151. package/coverage/lcov-report/threads/utils.js.html +14 -14
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
  154. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  155. package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
  156. package/coverage/lcov-report/utilities/global.js.html +26 -26
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +25 -25
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
  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 +1 -1
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +53 -53
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
  167. package/coverage/lcov-report/utilities/security.js.html +8 -8
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/usageQuota/index.html +141 -0
  170. package/coverage/lcov-report/utilities/usageQuota/index.js.html +356 -0
  171. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +302 -0
  172. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +134 -0
  173. package/coverage/lcov-report/utilities/users.js.html +5 -5
  174. package/coverage/lcov-report/utilities/workerRequests.js.html +39 -108
  175. package/coverage/lcov.info +2644 -2356
  176. package/dist/api/controllers/application.js +45 -24
  177. package/dist/api/controllers/datasource.js +11 -0
  178. package/dist/api/controllers/query/index.js +11 -3
  179. package/dist/api/controllers/row/utils.js +1 -2
  180. package/dist/api/controllers/static/index.js +59 -10
  181. package/dist/api/controllers/table/internal.js +2 -0
  182. package/dist/api/controllers/table/utils.js +5 -0
  183. package/dist/api/routes/index.js +0 -2
  184. package/dist/api/routes/static.js +2 -1
  185. package/dist/automations/steps/createRow.js +2 -4
  186. package/dist/automations/steps/deleteRow.js +1 -4
  187. package/dist/constants/index.js +3 -0
  188. package/dist/definitions/datasource.js +1 -0
  189. package/dist/environment.js +1 -0
  190. package/dist/integrations/googlesheets.js +340 -0
  191. package/dist/integrations/index.js +3 -0
  192. package/dist/integrations/utils.js +6 -3
  193. package/dist/middleware/currentapp.js +0 -9
  194. package/dist/middleware/usageQuota.js +82 -13
  195. package/dist/migrations/usageQuotas/index.js +24 -0
  196. package/dist/migrations/usageQuotas/syncApps.js +26 -0
  197. package/dist/migrations/usageQuotas/syncRows.js +29 -0
  198. package/dist/package.json +8 -5
  199. package/dist/tests/utilities/TestConfiguration.js +3 -1
  200. package/dist/threads/query.js +4 -0
  201. package/dist/tsconfig.tsbuildinfo +1 -1
  202. package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
  203. package/dist/utilities/usageQuota/rows.js +77 -0
  204. package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
  205. package/dist/utilities/workerRequests.js +0 -20
  206. package/nodemon.json +1 -1
  207. package/package.json +9 -6
  208. package/src/api/controllers/application.js +48 -27
  209. package/src/api/controllers/datasource.js +12 -0
  210. package/src/api/controllers/query/index.js +14 -3
  211. package/src/api/controllers/row/utils.js +1 -4
  212. package/src/api/controllers/static/index.js +63 -10
  213. package/src/api/controllers/table/internal.js +2 -0
  214. package/src/api/controllers/table/utils.js +5 -0
  215. package/src/api/routes/index.js +0 -2
  216. package/src/api/routes/static.js +5 -0
  217. package/src/api/routes/tests/application.spec.js +2 -2
  218. package/src/api/routes/tests/static.spec.js +98 -0
  219. package/src/automations/steps/createRow.js +2 -4
  220. package/src/automations/steps/deleteRow.js +1 -4
  221. package/src/constants/index.js +4 -0
  222. package/src/definitions/datasource.ts +3 -0
  223. package/src/environment.js +1 -0
  224. package/src/integrations/googlesheets.ts +353 -0
  225. package/src/integrations/index.ts +3 -0
  226. package/src/integrations/utils.ts +18 -5
  227. package/src/middleware/currentapp.js +0 -9
  228. package/src/middleware/tests/usageQuota.spec.js +18 -24
  229. package/src/middleware/usageQuota.js +93 -15
  230. package/src/migrations/tests/usageQuotas/index.spec.js +27 -0
  231. package/src/migrations/tests/usageQuotas/syncApps.spec.js +37 -0
  232. package/src/migrations/tests/usageQuotas/syncRows.spec.js +43 -0
  233. package/src/migrations/usageQuotas/index.js +24 -0
  234. package/src/migrations/usageQuotas/syncApps.js +18 -0
  235. package/src/migrations/usageQuotas/syncRows.js +21 -0
  236. package/src/tests/utilities/TestConfiguration.js +3 -1
  237. package/src/threads/query.js +5 -0
  238. package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
  239. package/src/utilities/usageQuota/index.js +92 -0
  240. package/src/utilities/usageQuota/rows.js +74 -0
  241. package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
  242. package/src/utilities/workerRequests.js +0 -23
  243. package/dist/api/controllers/hosting.js +0 -30
  244. package/dist/api/routes/hosting.js +0 -11
  245. package/src/api/controllers/hosting.js +0 -22
  246. package/src/api/routes/hosting.js +0 -13
  247. package/src/api/routes/tests/hosting.spec.js +0 -36
  248. package/src/utilities/usageQuota.js +0 -73
@@ -0,0 +1,340 @@
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 datasource_1 = require("../definitions/datasource");
13
+ const google_auth_library_1 = require("google-auth-library");
14
+ const utils_1 = require("./utils");
15
+ const constants_1 = require("../constants");
16
+ const google_spreadsheet_1 = require("google-spreadsheet");
17
+ var GoogleSheetsModule;
18
+ (function (GoogleSheetsModule) {
19
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy");
20
+ const { getScopedConfig } = require("@budibase/backend-core/db");
21
+ const { Configs } = require("@budibase/backend-core/constants");
22
+ const SCHEMA = {
23
+ plus: true,
24
+ auth: {
25
+ type: "google",
26
+ },
27
+ relationships: false,
28
+ docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
29
+ description: "Create and collaborate on online spreadsheets in real-time and from any device. ",
30
+ friendlyName: "Google Sheets",
31
+ datasource: {
32
+ spreadsheetId: {
33
+ type: datasource_1.DatasourceFieldTypes.STRING,
34
+ required: true,
35
+ },
36
+ },
37
+ query: {
38
+ create: {
39
+ type: datasource_1.QueryTypes.FIELDS,
40
+ fields: {
41
+ sheet: {
42
+ type: datasource_1.DatasourceFieldTypes.STRING,
43
+ required: true,
44
+ },
45
+ row: {
46
+ type: datasource_1.QueryTypes.JSON,
47
+ required: true,
48
+ },
49
+ },
50
+ },
51
+ read: {
52
+ type: datasource_1.QueryTypes.FIELDS,
53
+ fields: {
54
+ sheet: {
55
+ type: datasource_1.DatasourceFieldTypes.STRING,
56
+ required: true,
57
+ },
58
+ },
59
+ },
60
+ update: {
61
+ type: datasource_1.QueryTypes.FIELDS,
62
+ fields: {
63
+ sheet: {
64
+ type: datasource_1.DatasourceFieldTypes.STRING,
65
+ required: true,
66
+ },
67
+ rowIndex: {
68
+ type: datasource_1.DatasourceFieldTypes.STRING,
69
+ required: true,
70
+ },
71
+ row: {
72
+ type: datasource_1.QueryTypes.JSON,
73
+ required: true,
74
+ },
75
+ },
76
+ },
77
+ delete: {
78
+ type: datasource_1.QueryTypes.FIELDS,
79
+ fields: {
80
+ sheet: {
81
+ type: datasource_1.DatasourceFieldTypes.STRING,
82
+ required: true,
83
+ },
84
+ rowIndex: {
85
+ type: datasource_1.DatasourceFieldTypes.NUMBER,
86
+ required: true,
87
+ },
88
+ },
89
+ },
90
+ },
91
+ };
92
+ class GoogleSheetsIntegration {
93
+ constructor(config) {
94
+ this.tables = {};
95
+ this.schemaErrors = {};
96
+ this.config = config;
97
+ const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId);
98
+ this.client = new google_spreadsheet_1.GoogleSpreadsheet(spreadsheetId);
99
+ }
100
+ /**
101
+ * Pull the spreadsheet ID out from a valid google sheets URL
102
+ * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
103
+ * @returns spreadsheet Id of the google sheet
104
+ */
105
+ cleanSpreadsheetUrl(spreadsheetId) {
106
+ if (!spreadsheetId) {
107
+ throw new Error("You must set a spreadsheet ID in your configuration to fetch tables.");
108
+ }
109
+ const parts = spreadsheetId.split("/");
110
+ return parts.length > 5 ? parts[5] : spreadsheetId;
111
+ }
112
+ connect() {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ try {
115
+ // Initialise oAuth client
116
+ const db = getGlobalDB();
117
+ const googleConfig = yield getScopedConfig(db, {
118
+ type: Configs.GOOGLE,
119
+ });
120
+ const oauthClient = new google_auth_library_1.OAuth2Client({
121
+ clientId: googleConfig.clientID,
122
+ clientSecret: googleConfig.clientSecret,
123
+ });
124
+ oauthClient.credentials.access_token = this.config.auth.accessToken;
125
+ oauthClient.credentials.refresh_token = this.config.auth.refreshToken;
126
+ this.client.useOAuth2Client(oauthClient);
127
+ yield this.client.loadInfo();
128
+ }
129
+ catch (err) {
130
+ console.error("Error connecting to google sheets", err);
131
+ throw err;
132
+ }
133
+ });
134
+ }
135
+ buildSchema(datasourceId) {
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ yield this.connect();
138
+ const sheets = yield this.client.sheetsByIndex;
139
+ const tables = {};
140
+ for (let sheet of sheets) {
141
+ // must fetch rows to determine schema
142
+ yield sheet.getRows();
143
+ // build schema
144
+ const schema = {};
145
+ // build schema from headers
146
+ for (let header of sheet.headerValues) {
147
+ schema[header] = {
148
+ name: header,
149
+ type: constants_1.FieldTypes.STRING,
150
+ };
151
+ }
152
+ // create tables
153
+ tables[sheet.title] = {
154
+ _id: utils_1.buildExternalTableId(datasourceId, sheet.title),
155
+ name: sheet.title,
156
+ primary: ["rowNumber"],
157
+ schema,
158
+ };
159
+ }
160
+ this.tables = tables;
161
+ });
162
+ }
163
+ query(json) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ const sheet = json.endpoint.entityId;
166
+ const handlers = {
167
+ [constants_1.DataSourceOperation.CREATE]: () => this.create({ sheet, row: json.body }),
168
+ [constants_1.DataSourceOperation.READ]: () => this.read({ sheet }),
169
+ [constants_1.DataSourceOperation.UPDATE]: () => {
170
+ var _a, _b, _c;
171
+ return this.update({
172
+ // exclude the header row and zero index
173
+ rowIndex: ((_c = (_b = (_a = json.extra) === null || _a === void 0 ? void 0 : _a.idFilter) === null || _b === void 0 ? void 0 : _b.equal) === null || _c === void 0 ? void 0 : _c.rowNumber) - 2,
174
+ sheet,
175
+ row: json.body,
176
+ });
177
+ },
178
+ [constants_1.DataSourceOperation.DELETE]: () => {
179
+ var _a, _b, _c;
180
+ return this.delete({
181
+ // exclude the header row and zero index
182
+ rowIndex: ((_c = (_b = (_a = json.extra) === null || _a === void 0 ? void 0 : _a.idFilter) === null || _b === void 0 ? void 0 : _b.equal) === null || _c === void 0 ? void 0 : _c.rowNumber) - 2,
183
+ sheet,
184
+ });
185
+ },
186
+ [constants_1.DataSourceOperation.CREATE_TABLE]: () => { var _a; return this.createTable((_a = json === null || json === void 0 ? void 0 : json.table) === null || _a === void 0 ? void 0 : _a.name); },
187
+ [constants_1.DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
188
+ [constants_1.DataSourceOperation.DELETE_TABLE]: () => { var _a; return this.deleteTable((_a = json === null || json === void 0 ? void 0 : json.table) === null || _a === void 0 ? void 0 : _a.name); },
189
+ };
190
+ const internalQueryMethod = handlers[json.endpoint.operation];
191
+ return yield internalQueryMethod();
192
+ });
193
+ }
194
+ buildRowObject(headers, values, rowNumber) {
195
+ const rowObject = { rowNumber };
196
+ for (let i = 0; i < headers.length; i++) {
197
+ rowObject._id = rowNumber;
198
+ rowObject[headers[i]] = values[i];
199
+ }
200
+ return rowObject;
201
+ }
202
+ createTable(name) {
203
+ return __awaiter(this, void 0, void 0, function* () {
204
+ try {
205
+ yield this.connect();
206
+ const sheet = yield this.client.addSheet({ title: name });
207
+ return sheet;
208
+ }
209
+ catch (err) {
210
+ console.error("Error creating new table in google sheets", err);
211
+ throw err;
212
+ }
213
+ });
214
+ }
215
+ updateTable(table) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ try {
218
+ yield this.connect();
219
+ const sheet = yield this.client.sheetsByTitle[table.name];
220
+ yield sheet.loadHeaderRow();
221
+ if (table._rename) {
222
+ const headers = [];
223
+ for (let header of sheet.headerValues) {
224
+ if (header === table._rename.old) {
225
+ headers.push(table._rename.updated);
226
+ }
227
+ else {
228
+ headers.push(header);
229
+ }
230
+ }
231
+ yield sheet.setHeaderRow(headers);
232
+ }
233
+ else {
234
+ let newField = Object.keys(table.schema).find(key => !sheet.headerValues.includes(key));
235
+ yield sheet.setHeaderRow([...sheet.headerValues, newField]);
236
+ }
237
+ }
238
+ catch (err) {
239
+ console.error("Error updating table in google sheets", err);
240
+ throw err;
241
+ }
242
+ });
243
+ }
244
+ deleteTable(sheet) {
245
+ return __awaiter(this, void 0, void 0, function* () {
246
+ try {
247
+ yield this.connect();
248
+ const sheetToDelete = yield this.client.sheetsByTitle[sheet];
249
+ return yield sheetToDelete.delete();
250
+ }
251
+ catch (err) {
252
+ console.error("Error deleting table in google sheets", err);
253
+ throw err;
254
+ }
255
+ });
256
+ }
257
+ create(query) {
258
+ return __awaiter(this, void 0, void 0, function* () {
259
+ try {
260
+ yield this.connect();
261
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
262
+ const rowToInsert = typeof query.row === "string" ? JSON.parse(query.row) : query.row;
263
+ const row = yield sheet.addRow(rowToInsert);
264
+ return [
265
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
266
+ ];
267
+ }
268
+ catch (err) {
269
+ console.error("Error writing to google sheets", err);
270
+ throw err;
271
+ }
272
+ });
273
+ }
274
+ read(query) {
275
+ return __awaiter(this, void 0, void 0, function* () {
276
+ try {
277
+ yield this.connect();
278
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
279
+ const rows = yield sheet.getRows();
280
+ const headerValues = sheet.headerValues;
281
+ const response = [];
282
+ for (let row of rows) {
283
+ response.push(this.buildRowObject(headerValues, row._rawData, row._rowNumber));
284
+ }
285
+ return response;
286
+ }
287
+ catch (err) {
288
+ console.error("Error reading from google sheets", err);
289
+ throw err;
290
+ }
291
+ });
292
+ }
293
+ update(query) {
294
+ return __awaiter(this, void 0, void 0, function* () {
295
+ try {
296
+ yield this.connect();
297
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
298
+ const rows = yield sheet.getRows();
299
+ const row = rows[query.rowIndex];
300
+ if (row) {
301
+ const updateValues = query.row;
302
+ for (let key in updateValues) {
303
+ row[key] = updateValues[key];
304
+ }
305
+ yield row.save();
306
+ return [
307
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
308
+ ];
309
+ }
310
+ else {
311
+ throw new Error("Row does not exist.");
312
+ }
313
+ }
314
+ catch (err) {
315
+ console.error("Error reading from google sheets", err);
316
+ throw err;
317
+ }
318
+ });
319
+ }
320
+ delete(query) {
321
+ return __awaiter(this, void 0, void 0, function* () {
322
+ yield this.connect();
323
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
324
+ const rows = yield sheet.getRows();
325
+ const row = rows[query.rowIndex];
326
+ if (row) {
327
+ yield row.delete();
328
+ return [{ deleted: query.rowIndex }];
329
+ }
330
+ else {
331
+ throw new Error("Row does not exist.");
332
+ }
333
+ });
334
+ }
335
+ }
336
+ module.exports = {
337
+ schema: SCHEMA,
338
+ integration: GoogleSheetsIntegration,
339
+ };
340
+ })(GoogleSheetsModule || (GoogleSheetsModule = {}));
@@ -10,6 +10,7 @@ const airtable = require("./airtable");
10
10
  const mysql = require("./mysql");
11
11
  const arangodb = require("./arangodb");
12
12
  const rest = require("./rest");
13
+ const googlesheets = require("./googlesheets");
13
14
  const { SourceNames } = require("../definitions/datasource");
14
15
  const DEFINITIONS = {
15
16
  [SourceNames.POSTGRES]: postgres.schema,
@@ -23,6 +24,7 @@ const DEFINITIONS = {
23
24
  [SourceNames.MYSQL]: mysql.schema,
24
25
  [SourceNames.ARANGODB]: arangodb.schema,
25
26
  [SourceNames.REST]: rest.schema,
27
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.schema,
26
28
  };
27
29
  const INTEGRATIONS = {
28
30
  [SourceNames.POSTGRES]: postgres.integration,
@@ -36,6 +38,7 @@ const INTEGRATIONS = {
36
38
  [SourceNames.MYSQL]: mysql.integration,
37
39
  [SourceNames.ARANGODB]: arangodb.integration,
38
40
  [SourceNames.REST]: rest.integration,
41
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
39
42
  };
40
43
  // optionally add oracle integration if the oracle binary can be installed
41
44
  if (!(process.arch === "arm64" && process.platform === "darwin")) {
@@ -153,7 +153,9 @@ exports.isIsoDateString = isIsoDateString;
153
153
  * @param tableIds The IDs of the tables which currently exist.
154
154
  */
155
155
  function shouldCopyRelationship(column, tableIds) {
156
- return column.type === constants_1.FieldTypes.LINK && column.tableId && tableIds.includes(column.tableId);
156
+ return (column.type === constants_1.FieldTypes.LINK &&
157
+ column.tableId &&
158
+ tableIds.includes(column.tableId));
157
159
  }
158
160
  /**
159
161
  * Similar function to the shouldCopyRelationship function, but instead this looks for options and boolean
@@ -164,8 +166,9 @@ function shouldCopyRelationship(column, tableIds) {
164
166
  * @param fetchedColumn The fetched column to check for the type in the external database.
165
167
  */
166
168
  function shouldCopySpecialColumn(column, fetchedColumn) {
167
- return column.type === constants_1.FieldTypes.OPTIONS ||
168
- ((!fetchedColumn || fetchedColumn.type === constants_1.FieldTypes.NUMBER) && column.type === constants_1.FieldTypes.BOOLEAN);
169
+ return (column.type === constants_1.FieldTypes.OPTIONS ||
170
+ ((!fetchedColumn || fetchedColumn.type === constants_1.FieldTypes.NUMBER) &&
171
+ column.type === constants_1.FieldTypes.BOOLEAN));
169
172
  }
170
173
  /**
171
174
  * Looks for columns which need to be copied over into the new table definitions, like relationships
@@ -49,15 +49,6 @@ module.exports = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
49
49
  !isWebhookEndpoint(ctx) &&
50
50
  (!ctx.user || !ctx.user.builder || !ctx.user.builder.global)) {
51
51
  clearCookie(ctx, Cookies.CurrentApp);
52
- // have to set the return url on the server side as client side is not available
53
- setCookie(ctx, ctx.url, Cookies.RETURN_URL, {
54
- // don't sign so the browser can easily read
55
- sign: false,
56
- // use the request domain to match how ui handles the return url cookie.
57
- // it's important we don't use the shared domain here as the builder
58
- // can't delete from it without awareness of the domain.
59
- requestDomain: true,
60
- });
61
52
  return ctx.redirect("/");
62
53
  }
63
54
  let appId, roleId = BUILTIN_ROLE_IDS.PUBLIC;
@@ -10,11 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const CouchDB = require("../db");
12
12
  const usageQuota = require("../utilities/usageQuota");
13
- const env = require("../environment");
14
- const { getTenantId } = require("@budibase/backend-core/tenancy");
13
+ const { getUniqueRows } = require("../utilities/usageQuota/rows");
15
14
  const { isExternalTable, isRowId: isExternalRowId, } = require("../integrations/utils");
16
- // tenants without limits
17
- const EXCLUDED_TENANTS = ["bb", "default", "bbtest", "bbstaging"];
15
+ const migration = require("../migrations/usageQuotas");
18
16
  // currently only counting new writes and deletes
19
17
  const METHOD_MAP = {
20
18
  POST: 1,
@@ -22,13 +20,13 @@ const METHOD_MAP = {
22
20
  };
23
21
  const DOMAIN_MAP = {
24
22
  rows: usageQuota.Properties.ROW,
25
- upload: usageQuota.Properties.UPLOAD,
26
- views: usageQuota.Properties.VIEW,
27
- users: usageQuota.Properties.USER,
23
+ // upload: usageQuota.Properties.UPLOAD, // doesn't work yet
24
+ // views: usageQuota.Properties.VIEW, // doesn't work yet
25
+ // users: usageQuota.Properties.USER, // doesn't work yet
28
26
  applications: usageQuota.Properties.APPS,
29
27
  // this will not be updated by endpoint calls
30
28
  // instead it will be updated by triggerInfo
31
- automationRuns: usageQuota.Properties.AUTOMATION,
29
+ // automationRuns: usageQuota.Properties.AUTOMATION, // doesn't work yet
32
30
  };
33
31
  function getProperty(url) {
34
32
  for (let domain of Object.keys(DOMAIN_MAP)) {
@@ -38,9 +36,7 @@ function getProperty(url) {
38
36
  }
39
37
  }
40
38
  module.exports = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
41
- const tenantId = getTenantId();
42
- // if in development or a self hosted cloud usage quotas should not be executed
43
- if (env.isDev() || env.SELF_HOSTED || EXCLUDED_TENANTS.includes(tenantId)) {
39
+ if (!usageQuota.useQuotas()) {
44
40
  return next();
45
41
  }
46
42
  let usage = METHOD_MAP[ctx.req.method];
@@ -78,10 +74,83 @@ module.exports = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
78
74
  usage = files.map(file => file.size).reduce((total, size) => total + size);
79
75
  }
80
76
  try {
81
- yield usageQuota.update(property, usage);
82
- return next();
77
+ yield migration.run();
78
+ yield performRequest(ctx, next, property, usage);
83
79
  }
84
80
  catch (err) {
85
81
  ctx.throw(400, err);
86
82
  }
87
83
  });
84
+ const performRequest = (ctx, next, property, usage) => __awaiter(void 0, void 0, void 0, function* () {
85
+ const usageContext = {
86
+ skipNext: false,
87
+ skipUsage: false,
88
+ [usageQuota.Properties.APPS]: {},
89
+ };
90
+ if (usage === -1) {
91
+ if (PRE_DELETE[property]) {
92
+ yield PRE_DELETE[property](ctx, usageContext);
93
+ }
94
+ }
95
+ else {
96
+ if (PRE_CREATE[property]) {
97
+ yield PRE_CREATE[property](ctx, usageContext);
98
+ }
99
+ }
100
+ // run the request
101
+ if (!usageContext.skipNext) {
102
+ yield usageQuota.update(property, usage, { dryRun: true });
103
+ yield next();
104
+ }
105
+ if (usage === -1) {
106
+ if (POST_DELETE[property]) {
107
+ yield POST_DELETE[property](ctx, usageContext);
108
+ }
109
+ }
110
+ else {
111
+ if (POST_CREATE[property]) {
112
+ yield POST_CREATE[property](ctx, usageContext);
113
+ }
114
+ }
115
+ // update the usage
116
+ if (!usageContext.skipUsage) {
117
+ yield usageQuota.update(property, usage);
118
+ }
119
+ });
120
+ const appPreDelete = (ctx, usageContext) => __awaiter(void 0, void 0, void 0, function* () {
121
+ if (ctx.query.unpublish) {
122
+ // don't run usage decrement for unpublish
123
+ usageContext.skipUsage = true;
124
+ return;
125
+ }
126
+ // store the row count to delete
127
+ const rows = yield getUniqueRows([ctx.appId]);
128
+ if (rows.length) {
129
+ usageContext[usageQuota.Properties.APPS] = { rowCount: rows.length };
130
+ }
131
+ });
132
+ const appPostDelete = (ctx, usageContext) => __awaiter(void 0, void 0, void 0, function* () {
133
+ // delete the app rows from usage
134
+ const rowCount = usageContext[usageQuota.Properties.APPS].rowCount;
135
+ if (rowCount) {
136
+ yield usageQuota.update(usageQuota.Properties.ROW, -rowCount);
137
+ }
138
+ });
139
+ const appPostCreate = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
140
+ // app import & template creation
141
+ if (ctx.request.body.useTemplate === "true") {
142
+ const rows = yield getUniqueRows([ctx.response.body.appId]);
143
+ const rowCount = rows ? rows.length : 0;
144
+ yield usageQuota.update(usageQuota.Properties.ROW, rowCount);
145
+ }
146
+ });
147
+ const PRE_DELETE = {
148
+ [usageQuota.Properties.APPS]: appPreDelete,
149
+ };
150
+ const POST_DELETE = {
151
+ [usageQuota.Properties.APPS]: appPostDelete,
152
+ };
153
+ const PRE_CREATE = {};
154
+ const POST_CREATE = {
155
+ [usageQuota.Properties.APPS]: appPostCreate,
156
+ };
@@ -0,0 +1,24 @@
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
+ const { MIGRATIONS, MIGRATION_DBS, migrateIfRequired, } = require("@budibase/backend-core/migrations");
12
+ const { useQuotas } = require("../../utilities/usageQuota");
13
+ const syncApps = require("./syncApps");
14
+ const syncRows = require("./syncRows");
15
+ exports.run = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ if (!useQuotas()) {
17
+ return;
18
+ }
19
+ // Jan 2022
20
+ yield migrateIfRequired(MIGRATION_DBS.GLOBAL_DB, MIGRATIONS.QUOTAS_1, () => __awaiter(void 0, void 0, void 0, function* () {
21
+ yield syncApps.run();
22
+ yield syncRows.run();
23
+ }));
24
+ });
@@ -0,0 +1,26 @@
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
+ const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy");
12
+ const { getAllApps } = require("@budibase/backend-core/db");
13
+ const CouchDB = require("../../db");
14
+ const { getUsageQuotaDoc } = require("../../utilities/usageQuota");
15
+ exports.run = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ const db = getGlobalDB();
17
+ // get app count
18
+ const devApps = yield getAllApps(CouchDB, { dev: true });
19
+ const appCount = devApps ? devApps.length : 0;
20
+ // sync app count
21
+ const tenantId = getTenantId();
22
+ console.log(`[Tenant: ${tenantId}] Syncing app count: ${appCount}`);
23
+ const usageDoc = yield getUsageQuotaDoc(db);
24
+ usageDoc.usageQuota.apps = appCount;
25
+ yield db.put(usageDoc);
26
+ });
@@ -0,0 +1,29 @@
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
+ const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy");
12
+ const { getAllApps } = require("@budibase/backend-core/db");
13
+ const CouchDB = require("../../db");
14
+ const { getUsageQuotaDoc } = require("../../utilities/usageQuota");
15
+ const { getUniqueRows } = require("../../utilities/usageQuota/rows");
16
+ exports.run = () => __awaiter(void 0, void 0, void 0, function* () {
17
+ const db = getGlobalDB();
18
+ // get all rows in all apps
19
+ const allApps = yield getAllApps(CouchDB, { all: true });
20
+ const appIds = allApps ? allApps.map(app => app.appId) : [];
21
+ const rows = yield getUniqueRows(appIds);
22
+ const rowCount = rows ? rows.length : 0;
23
+ // sync row count
24
+ const tenantId = getTenantId();
25
+ console.log(`[Tenant: ${tenantId}] Syncing row count: ${rowCount}`);
26
+ const usageDoc = yield getUsageQuotaDoc(db);
27
+ usageDoc.usageQuota.rows = rowCount;
28
+ yield db.put(usageDoc);
29
+ });
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "1.0.46-alpha.1",
4
+ "version": "1.0.46-alpha.5",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -70,9 +70,9 @@
70
70
  "license": "GPL-3.0",
71
71
  "dependencies": {
72
72
  "@apidevtools/swagger-parser": "^10.0.3",
73
- "@budibase/backend-core": "^1.0.46-alpha.1",
74
- "@budibase/client": "^1.0.46-alpha.1",
75
- "@budibase/string-templates": "^1.0.46-alpha.1",
73
+ "@budibase/backend-core": "^1.0.46-alpha.5",
74
+ "@budibase/client": "^1.0.46-alpha.5",
75
+ "@budibase/string-templates": "^1.0.46-alpha.5",
76
76
  "@bull-board/api": "^3.7.0",
77
77
  "@bull-board/koa": "^3.7.0",
78
78
  "@elastic/elasticsearch": "7.10.0",
@@ -92,6 +92,8 @@
92
92
  "fix-path": "3.0.0",
93
93
  "form-data": "^4.0.0",
94
94
  "fs-extra": "8.1.0",
95
+ "google-auth-library": "^7.11.0",
96
+ "google-spreadsheet": "^3.2.0",
95
97
  "jimp": "0.16.1",
96
98
  "joi": "17.2.1",
97
99
  "js-yaml": "^4.1.0",
@@ -110,7 +112,7 @@
110
112
  "mongodb": "3.6.3",
111
113
  "mssql": "6.2.3",
112
114
  "mysql2": "^2.3.1",
113
- "node-fetch": "2.6.0",
115
+ "node-fetch": "2.6.7",
114
116
  "open": "^8.4.0",
115
117
  "pg": "8.5.1",
116
118
  "pino-pretty": "4.0.0",
@@ -139,6 +141,7 @@
139
141
  "@jest/test-sequencer": "^24.8.0",
140
142
  "@types/apidoc": "^0.50.0",
141
143
  "@types/bull": "^3.15.1",
144
+ "@types/google-spreadsheet": "^3.1.5",
142
145
  "@types/jest": "^26.0.23",
143
146
  "@types/koa": "^2.13.3",
144
147
  "@types/koa-router": "^7.4.2",