@budibase/server 2.4.40 → 2.4.42-alpha.0
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.
- package/__mocks__/node-fetch.ts +6 -1
- package/builder/assets/index.3cb1022d.css +6 -0
- package/builder/assets/{index.07ed2ead.js → index.4b6c8c0e.js} +384 -383
- package/builder/index.html +7 -7
- package/dist/api/controllers/application.js +28 -24
- package/dist/api/controllers/datasource.js +2 -1
- package/dist/api/controllers/public/metrics.js +113 -0
- package/dist/api/controllers/row/external.js +16 -8
- package/dist/api/controllers/row/index.js +11 -1
- package/dist/api/controllers/row/internal.js +1 -10
- package/dist/api/controllers/row/utils.js +7 -7
- package/dist/api/controllers/static/index.js +84 -24
- package/dist/api/controllers/static/templates/BudibaseApp.svelte +33 -10
- package/dist/api/controllers/table/external.js +16 -12
- package/dist/api/controllers/table/utils.js +15 -1
- package/dist/api/routes/public/index.js +8 -0
- package/dist/api/routes/public/metrics.js +30 -0
- package/dist/app.js +1 -0
- package/dist/constants/index.js +2 -1
- package/dist/integrations/googlesheets.js +125 -59
- package/dist/integrations/redis.js +1 -1
- package/dist/integrations/utils.js +17 -2
- package/dist/package.json +13 -12
- package/dist/sdk/users/utils.js +2 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/global.js +17 -7
- package/jest.config.ts +1 -0
- package/package.json +14 -13
- package/scripts/test.sh +3 -3
- package/specs/openapi.json +39 -0
- package/specs/openapi.yaml +169 -0
- package/specs/resources/application.ts +11 -0
- package/specs/resources/index.ts +2 -0
- package/specs/resources/metrics.ts +81 -0
- package/src/api/controllers/application.ts +20 -21
- package/src/api/controllers/datasource.ts +2 -1
- package/src/api/controllers/public/metrics.ts +251 -0
- package/src/api/controllers/row/external.ts +26 -16
- package/src/api/controllers/row/index.ts +12 -2
- package/src/api/controllers/row/internal.ts +0 -7
- package/src/api/controllers/row/utils.ts +7 -7
- package/src/api/controllers/static/index.ts +69 -26
- package/src/api/controllers/static/templates/BudibaseApp.svelte +33 -10
- package/src/api/controllers/table/external.ts +24 -17
- package/src/api/controllers/table/index.ts +9 -9
- package/src/api/controllers/table/utils.ts +18 -2
- package/src/api/controllers/view/tests/__snapshots__/viewBuilder.spec.js.snap +48 -48
- package/src/api/routes/public/index.ts +10 -1
- package/src/api/routes/public/metrics.ts +28 -0
- package/src/api/routes/public/tests/metrics.spec.js +34 -0
- package/src/api/routes/tests/__snapshots__/datasource.spec.ts.snap +22 -22
- package/src/api/routes/tests/__snapshots__/view.spec.js.snap +5 -5
- package/src/api/routes/tests/appSync.spec.ts +31 -0
- package/src/api/routes/tests/internalSearch.spec.js +8 -7
- package/src/app.ts +2 -1
- package/src/automations/automationUtils.ts +1 -1
- package/src/automations/tests/automation.spec.ts +99 -0
- package/src/constants/index.ts +1 -0
- package/src/definitions/openapi.ts +15 -0
- package/src/integration-test/postgres.spec.ts +46 -52
- package/src/integrations/googlesheets.ts +143 -71
- package/src/integrations/redis.ts +1 -1
- package/src/integrations/tests/googlesheets.spec.ts +13 -13
- package/src/integrations/tests/redis.spec.ts +9 -5
- package/src/integrations/utils.ts +16 -4
- package/src/middleware/currentapp.ts +2 -2
- package/src/sdk/users/utils.ts +4 -1
- package/src/tests/jestEnv.ts +1 -0
- package/src/tests/jestSetup.ts +5 -1
- package/src/tests/utilities/TestConfiguration.ts +13 -0
- package/src/tests/utilities/structures.ts +13 -1
- package/src/utilities/global.ts +21 -9
- package/builder/assets/favicon.e7fc7733.png +0 -0
- package/builder/assets/index.b0e3aca6.css +0 -6
- package/src/automations/tests/automation.spec.js +0 -84
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
cache,
|
|
21
21
|
tenancy,
|
|
22
22
|
context,
|
|
23
|
-
errors,
|
|
24
23
|
events,
|
|
25
24
|
migrations,
|
|
26
25
|
objectStore,
|
|
26
|
+
ErrorCode,
|
|
27
27
|
} from "@budibase/backend-core"
|
|
28
28
|
import { USERS_TABLE_SCHEMA } from "../../constants"
|
|
29
29
|
import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default"
|
|
@@ -44,7 +44,6 @@ import {
|
|
|
44
44
|
Layout,
|
|
45
45
|
Screen,
|
|
46
46
|
MigrationType,
|
|
47
|
-
BBContext,
|
|
48
47
|
Database,
|
|
49
48
|
UserCtx,
|
|
50
49
|
} from "@budibase/types"
|
|
@@ -74,14 +73,14 @@ async function getScreens() {
|
|
|
74
73
|
).rows.map((row: any) => row.doc)
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
function getUserRoleId(ctx:
|
|
76
|
+
function getUserRoleId(ctx: UserCtx) {
|
|
78
77
|
return !ctx.user?.role || !ctx.user.role._id
|
|
79
78
|
? roles.BUILTIN_ROLE_IDS.PUBLIC
|
|
80
79
|
: ctx.user.role._id
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
function checkAppUrl(
|
|
84
|
-
ctx:
|
|
83
|
+
ctx: UserCtx,
|
|
85
84
|
apps: App[],
|
|
86
85
|
url: string,
|
|
87
86
|
currentAppId?: string
|
|
@@ -95,7 +94,7 @@ function checkAppUrl(
|
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
function checkAppName(
|
|
98
|
-
ctx:
|
|
97
|
+
ctx: UserCtx,
|
|
99
98
|
apps: App[],
|
|
100
99
|
name: string,
|
|
101
100
|
currentAppId?: string
|
|
@@ -160,7 +159,7 @@ async function addDefaultTables(db: Database) {
|
|
|
160
159
|
await db.bulkDocs([...defaultDbDocs])
|
|
161
160
|
}
|
|
162
161
|
|
|
163
|
-
export async function fetch(ctx:
|
|
162
|
+
export async function fetch(ctx: UserCtx) {
|
|
164
163
|
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
|
165
164
|
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
|
166
165
|
const apps = (await dbCore.getAllApps({ dev, all })) as App[]
|
|
@@ -185,7 +184,7 @@ export async function fetch(ctx: BBContext) {
|
|
|
185
184
|
ctx.body = await checkAppMetadata(apps)
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
export async function fetchAppDefinition(ctx:
|
|
187
|
+
export async function fetchAppDefinition(ctx: UserCtx) {
|
|
189
188
|
const layouts = await getLayouts()
|
|
190
189
|
const userRoleId = getUserRoleId(ctx)
|
|
191
190
|
const accessController = new roles.AccessController()
|
|
@@ -231,7 +230,7 @@ export async function fetchAppPackage(ctx: UserCtx) {
|
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
232
|
|
|
234
|
-
async function performAppCreate(ctx:
|
|
233
|
+
async function performAppCreate(ctx: UserCtx) {
|
|
235
234
|
const apps = (await dbCore.getAllApps({ dev: true })) as App[]
|
|
236
235
|
const name = ctx.request.body.name,
|
|
237
236
|
possibleUrl = ctx.request.body.url
|
|
@@ -360,7 +359,7 @@ async function creationEvents(request: any, app: App) {
|
|
|
360
359
|
}
|
|
361
360
|
}
|
|
362
361
|
|
|
363
|
-
async function appPostCreate(ctx:
|
|
362
|
+
async function appPostCreate(ctx: UserCtx, app: App) {
|
|
364
363
|
const tenantId = tenancy.getTenantId()
|
|
365
364
|
await migrations.backPopulateMigrations({
|
|
366
365
|
type: MigrationType.APP,
|
|
@@ -378,7 +377,7 @@ async function appPostCreate(ctx: BBContext, app: App) {
|
|
|
378
377
|
return quotas.addRows(rowCount)
|
|
379
378
|
})
|
|
380
379
|
} catch (err: any) {
|
|
381
|
-
if (err.code && err.code ===
|
|
380
|
+
if (err.code && err.code === ErrorCode.USAGE_LIMIT_EXCEEDED) {
|
|
382
381
|
// this import resulted in row usage exceeding the quota
|
|
383
382
|
// delete the app
|
|
384
383
|
// skip pre and post-steps as no rows have been added to quotas yet
|
|
@@ -391,7 +390,7 @@ async function appPostCreate(ctx: BBContext, app: App) {
|
|
|
391
390
|
}
|
|
392
391
|
}
|
|
393
392
|
|
|
394
|
-
export async function create(ctx:
|
|
393
|
+
export async function create(ctx: UserCtx) {
|
|
395
394
|
const newApplication = await quotas.addApp(() => performAppCreate(ctx))
|
|
396
395
|
await appPostCreate(ctx, newApplication)
|
|
397
396
|
await cache.bustCache(cache.CacheKey.CHECKLIST)
|
|
@@ -401,7 +400,7 @@ export async function create(ctx: BBContext) {
|
|
|
401
400
|
|
|
402
401
|
// This endpoint currently operates as a PATCH rather than a PUT
|
|
403
402
|
// Thus name and url fields are handled only if present
|
|
404
|
-
export async function update(ctx:
|
|
403
|
+
export async function update(ctx: UserCtx) {
|
|
405
404
|
const apps = (await dbCore.getAllApps({ dev: true })) as App[]
|
|
406
405
|
// validation
|
|
407
406
|
const name = ctx.request.body.name,
|
|
@@ -421,7 +420,7 @@ export async function update(ctx: BBContext) {
|
|
|
421
420
|
ctx.body = app
|
|
422
421
|
}
|
|
423
422
|
|
|
424
|
-
export async function updateClient(ctx:
|
|
423
|
+
export async function updateClient(ctx: UserCtx) {
|
|
425
424
|
// Get current app version
|
|
426
425
|
const db = context.getAppDB()
|
|
427
426
|
const application = await db.get(DocumentType.APP_METADATA)
|
|
@@ -445,7 +444,7 @@ export async function updateClient(ctx: BBContext) {
|
|
|
445
444
|
ctx.body = app
|
|
446
445
|
}
|
|
447
446
|
|
|
448
|
-
export async function revertClient(ctx:
|
|
447
|
+
export async function revertClient(ctx: UserCtx) {
|
|
449
448
|
// Check app can be reverted
|
|
450
449
|
const db = context.getAppDB()
|
|
451
450
|
const application = await db.get(DocumentType.APP_METADATA)
|
|
@@ -471,7 +470,7 @@ export async function revertClient(ctx: BBContext) {
|
|
|
471
470
|
ctx.body = app
|
|
472
471
|
}
|
|
473
472
|
|
|
474
|
-
|
|
473
|
+
async function unpublishApp(ctx: UserCtx) {
|
|
475
474
|
let appId = ctx.params.appId
|
|
476
475
|
appId = dbCore.getProdAppID(appId)
|
|
477
476
|
|
|
@@ -487,7 +486,7 @@ const unpublishApp = async (ctx: any) => {
|
|
|
487
486
|
return result
|
|
488
487
|
}
|
|
489
488
|
|
|
490
|
-
async function destroyApp(ctx:
|
|
489
|
+
async function destroyApp(ctx: UserCtx) {
|
|
491
490
|
let appId = ctx.params.appId
|
|
492
491
|
appId = dbCore.getProdAppID(appId)
|
|
493
492
|
const devAppId = dbCore.getDevAppID(appId)
|
|
@@ -515,12 +514,12 @@ async function destroyApp(ctx: BBContext) {
|
|
|
515
514
|
return result
|
|
516
515
|
}
|
|
517
516
|
|
|
518
|
-
async function preDestroyApp(ctx:
|
|
517
|
+
async function preDestroyApp(ctx: UserCtx) {
|
|
519
518
|
const { rows } = await getUniqueRows([ctx.params.appId])
|
|
520
519
|
ctx.rowCount = rows.length
|
|
521
520
|
}
|
|
522
521
|
|
|
523
|
-
async function postDestroyApp(ctx:
|
|
522
|
+
async function postDestroyApp(ctx: UserCtx) {
|
|
524
523
|
const rowCount = ctx.rowCount
|
|
525
524
|
await groups.cleanupApp(ctx.params.appId)
|
|
526
525
|
if (rowCount) {
|
|
@@ -528,7 +527,7 @@ async function postDestroyApp(ctx: BBContext) {
|
|
|
528
527
|
}
|
|
529
528
|
}
|
|
530
529
|
|
|
531
|
-
export async function destroy(ctx:
|
|
530
|
+
export async function destroy(ctx: UserCtx) {
|
|
532
531
|
await preDestroyApp(ctx)
|
|
533
532
|
const result = await destroyApp(ctx)
|
|
534
533
|
await postDestroyApp(ctx)
|
|
@@ -536,7 +535,7 @@ export async function destroy(ctx: BBContext) {
|
|
|
536
535
|
ctx.body = result
|
|
537
536
|
}
|
|
538
537
|
|
|
539
|
-
export
|
|
538
|
+
export async function unpublish(ctx: UserCtx) {
|
|
540
539
|
const prodAppId = dbCore.getProdAppID(ctx.params.appId)
|
|
541
540
|
const dbExists = await dbCore.dbExists(prodAppId)
|
|
542
541
|
|
|
@@ -551,7 +550,7 @@ export const unpublish = async (ctx: BBContext) => {
|
|
|
551
550
|
ctx.status = 204
|
|
552
551
|
}
|
|
553
552
|
|
|
554
|
-
export async function sync(ctx:
|
|
553
|
+
export async function sync(ctx: UserCtx) {
|
|
555
554
|
const appId = ctx.params.appId
|
|
556
555
|
try {
|
|
557
556
|
ctx.body = await sdk.applications.syncApp(appId)
|
|
@@ -84,8 +84,9 @@ export async function buildSchemaFromDb(ctx: UserCtx) {
|
|
|
84
84
|
setDefaultDisplayColumns(datasource)
|
|
85
85
|
const dbResp = await db.put(datasource)
|
|
86
86
|
datasource._rev = dbResp.rev
|
|
87
|
+
const cleanedDatasource = await sdk.datasources.removeSecretSingle(datasource)
|
|
87
88
|
|
|
88
|
-
const response: any = { datasource }
|
|
89
|
+
const response: any = { datasource: cleanedDatasource }
|
|
89
90
|
if (error) {
|
|
90
91
|
response.error = error
|
|
91
92
|
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Ctx } from "@budibase/types"
|
|
2
|
+
import { users as userCore, db as dbCore } from "@budibase/backend-core"
|
|
3
|
+
import { quotas, licensing } from "@budibase/pro"
|
|
4
|
+
|
|
5
|
+
import os from "os"
|
|
6
|
+
|
|
7
|
+
export async function fetch(ctx: Ctx) {
|
|
8
|
+
// *** OPERATING SYSTEM ***
|
|
9
|
+
const freeMem = os.freemem()
|
|
10
|
+
const totalMem = os.totalmem()
|
|
11
|
+
const usedMem = totalMem - freeMem
|
|
12
|
+
const uptime = os.uptime()
|
|
13
|
+
|
|
14
|
+
// *** APPS ***
|
|
15
|
+
const allDatabases = await dbCore.getAllDbs()
|
|
16
|
+
const devAppIDs = await dbCore.getDevAppIDs()
|
|
17
|
+
const prodAppIDs = await dbCore.getProdAppIDs()
|
|
18
|
+
const allAppIds = await dbCore.getAllApps({ idsOnly: true })
|
|
19
|
+
|
|
20
|
+
// *** USERS ***
|
|
21
|
+
const usersObject = await userCore.getAllUserIds()
|
|
22
|
+
|
|
23
|
+
// *** QUOTAS ***
|
|
24
|
+
const usage = await quotas.getQuotaUsage()
|
|
25
|
+
const license = await licensing.cache.getCachedLicense()
|
|
26
|
+
const appsQuotaUsage = usage.usageQuota.apps
|
|
27
|
+
const rowsQuotaUsage = usage.usageQuota.rows
|
|
28
|
+
const pluginsQuotaUsage = usage.usageQuota.plugins
|
|
29
|
+
const userGroupsQuotaUsage = usage.usageQuota.userGroups
|
|
30
|
+
const queryQuotaUsage = usage.monthly.current.queries
|
|
31
|
+
const automationsQuotaUsage = usage.monthly.current.automations
|
|
32
|
+
const appsQuotaLimit = license.quotas.usage.static.apps.value
|
|
33
|
+
const rowsQuotaLimit = license.quotas.usage.static.rows.value
|
|
34
|
+
const userGroupsQuotaLimit = license.quotas.usage.static.userGroups.value
|
|
35
|
+
const pluginsQuotaLimit = license.quotas.usage.static.plugins.value
|
|
36
|
+
const queryQuotaLimit = license.quotas.usage.monthly.queries.value
|
|
37
|
+
const automationsQuotaLimit = license.quotas.usage.monthly.automations.value
|
|
38
|
+
|
|
39
|
+
// *** BUILD THE OUTPUT STRING ***
|
|
40
|
+
var outputString = ""
|
|
41
|
+
|
|
42
|
+
// **** budibase_os_uptime ****
|
|
43
|
+
outputString += convertToOpenMetrics(
|
|
44
|
+
"budibase_os_uptime",
|
|
45
|
+
"Time in seconds that the host operating system has been up",
|
|
46
|
+
"counter",
|
|
47
|
+
uptime
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
// **** budibase_os_free_mem ****
|
|
51
|
+
outputString += convertToOpenMetrics(
|
|
52
|
+
"budibase_os_free_mem",
|
|
53
|
+
"Bytes of memory free for usage on the host operating system",
|
|
54
|
+
"gauge",
|
|
55
|
+
freeMem
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// **** budibase_os_total_mem ****
|
|
59
|
+
outputString += convertToOpenMetrics(
|
|
60
|
+
"budibase_os_total_mem",
|
|
61
|
+
"Total bytes of memory on the host operating system",
|
|
62
|
+
"gauge",
|
|
63
|
+
totalMem
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// **** budibase_os_used_mem ****
|
|
67
|
+
outputString += convertToOpenMetrics(
|
|
68
|
+
"budibase_os_used_mem",
|
|
69
|
+
"Total bytes of memory in use on the host operating system",
|
|
70
|
+
"gauge",
|
|
71
|
+
usedMem
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
// **** budibase_os_load1 ****
|
|
75
|
+
outputString += convertToOpenMetrics(
|
|
76
|
+
"budibase_os_load1",
|
|
77
|
+
"Host operating system load average",
|
|
78
|
+
"gauge",
|
|
79
|
+
os.loadavg()[0]
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
// **** budibase_os_load5 ****
|
|
83
|
+
outputString += convertToOpenMetrics(
|
|
84
|
+
"budibase_os_load5",
|
|
85
|
+
"Host operating system load average",
|
|
86
|
+
"gauge",
|
|
87
|
+
os.loadavg()[1]
|
|
88
|
+
)
|
|
89
|
+
// **** budibase_os_load15 ****
|
|
90
|
+
outputString += convertToOpenMetrics(
|
|
91
|
+
"budibase_os_load15",
|
|
92
|
+
"Host operating system load average",
|
|
93
|
+
"gauge",
|
|
94
|
+
os.loadavg()[2]
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
// **** budibase_tenant_user_count ****
|
|
98
|
+
outputString += convertToOpenMetrics(
|
|
99
|
+
"budibase_tenant_user_count",
|
|
100
|
+
"The number of users created",
|
|
101
|
+
"gauge",
|
|
102
|
+
usersObject.length
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
// **** budibase_tenant_app_count ****
|
|
106
|
+
outputString += convertToOpenMetrics(
|
|
107
|
+
"budibase_tenant_app_count",
|
|
108
|
+
"The number of apps created by a user",
|
|
109
|
+
"gauge",
|
|
110
|
+
allAppIds.length
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
// **** budibase_tenant_production_app_count ****
|
|
114
|
+
outputString += convertToOpenMetrics(
|
|
115
|
+
"budibase_tenant_production_app_count",
|
|
116
|
+
"The number of apps a user has published",
|
|
117
|
+
"gauge",
|
|
118
|
+
prodAppIDs.length
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
// **** budibase_tenant_dev_app_count ****
|
|
122
|
+
outputString += convertToOpenMetrics(
|
|
123
|
+
"budibase_tenant_dev_app_count",
|
|
124
|
+
"The number of apps a user has unpublished in development",
|
|
125
|
+
"gauge",
|
|
126
|
+
devAppIDs.length
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
// **** budibase_tenant_db_count ****
|
|
130
|
+
outputString += convertToOpenMetrics(
|
|
131
|
+
"budibase_tenant_db_count",
|
|
132
|
+
"The number of couchdb databases including global tables such as _users",
|
|
133
|
+
"gauge",
|
|
134
|
+
allDatabases.length
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
// **** budibase_quota_usage_apps ****
|
|
138
|
+
outputString += convertToOpenMetrics(
|
|
139
|
+
"budibase_quota_usage_apps",
|
|
140
|
+
"The number of apps created",
|
|
141
|
+
"gauge",
|
|
142
|
+
appsQuotaUsage
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
// **** budibase_quota_limit_apps ****
|
|
146
|
+
outputString += convertToOpenMetrics(
|
|
147
|
+
"budibase_quota_limit_apps",
|
|
148
|
+
"The limit on the number of apps that can be created",
|
|
149
|
+
"gauge",
|
|
150
|
+
appsQuotaLimit == -1 ? Number.MAX_SAFE_INTEGER : appsQuotaLimit
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// **** budibase_quota_usage_rows ****
|
|
154
|
+
outputString += convertToOpenMetrics(
|
|
155
|
+
"budibase_quota_usage_rows",
|
|
156
|
+
"The number of database rows used from the quota",
|
|
157
|
+
"gauge",
|
|
158
|
+
rowsQuotaUsage
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
// **** budibase_quota_limit_rows ****
|
|
162
|
+
outputString += convertToOpenMetrics(
|
|
163
|
+
"budibase_quota_limit_rows",
|
|
164
|
+
"The limit on the number of rows that can be created",
|
|
165
|
+
"gauge",
|
|
166
|
+
rowsQuotaLimit == -1 ? Number.MAX_SAFE_INTEGER : rowsQuotaLimit
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
// **** budibase_quota_usage_plugins ****
|
|
170
|
+
outputString += convertToOpenMetrics(
|
|
171
|
+
"budibase_quota_usage_plugins",
|
|
172
|
+
"The number of plugins in use",
|
|
173
|
+
"gauge",
|
|
174
|
+
pluginsQuotaUsage
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
// **** budibase_quota_limit_plugins ****
|
|
178
|
+
outputString += convertToOpenMetrics(
|
|
179
|
+
"budibase_quota_limit_plugins",
|
|
180
|
+
"The limit on the number of plugins that can be created",
|
|
181
|
+
"gauge",
|
|
182
|
+
pluginsQuotaLimit == -1 ? Number.MAX_SAFE_INTEGER : pluginsQuotaLimit
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
// **** budibase_quota_usage_user_groups ****
|
|
186
|
+
outputString += convertToOpenMetrics(
|
|
187
|
+
"budibase_quota_usage_user_groups",
|
|
188
|
+
"The number of user groups created",
|
|
189
|
+
"gauge",
|
|
190
|
+
userGroupsQuotaUsage
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// **** budibase_quota_limit_user_groups ****
|
|
194
|
+
outputString += convertToOpenMetrics(
|
|
195
|
+
"budibase_quota_limit_user_groups",
|
|
196
|
+
"The limit on the number of user groups that can be created",
|
|
197
|
+
"gauge",
|
|
198
|
+
userGroupsQuotaLimit == -1 ? Number.MAX_SAFE_INTEGER : userGroupsQuotaLimit
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
// **** budibase_quota_usage_queries ****
|
|
202
|
+
outputString += convertToOpenMetrics(
|
|
203
|
+
"budibase_quota_usage_queries",
|
|
204
|
+
"The number of queries used in the current month",
|
|
205
|
+
"gauge",
|
|
206
|
+
queryQuotaUsage
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
// **** budibase_quota_limit_queries ****
|
|
210
|
+
outputString += convertToOpenMetrics(
|
|
211
|
+
"budibase_quota_limit_queries",
|
|
212
|
+
"The limit on the number of queries for the current month",
|
|
213
|
+
"gauge",
|
|
214
|
+
queryQuotaLimit == -1 ? Number.MAX_SAFE_INTEGER : queryQuotaLimit
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
// **** budibase_quota_usage_automations ****
|
|
218
|
+
outputString += convertToOpenMetrics(
|
|
219
|
+
"budibase_quota_usage_automations",
|
|
220
|
+
"The number of automations used in the current month",
|
|
221
|
+
"gauge",
|
|
222
|
+
automationsQuotaUsage
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
// **** budibase_quota_limit_automations ****
|
|
226
|
+
outputString += convertToOpenMetrics(
|
|
227
|
+
"budibase_quota_limit_automations",
|
|
228
|
+
"The limit on the number of automations that can be created",
|
|
229
|
+
"gauge",
|
|
230
|
+
automationsQuotaLimit == -1
|
|
231
|
+
? Number.MAX_SAFE_INTEGER
|
|
232
|
+
: automationsQuotaLimit
|
|
233
|
+
)
|
|
234
|
+
ctx.body = outputString
|
|
235
|
+
ctx.set("Content-Type", "text/plain")
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function convertToOpenMetrics(
|
|
239
|
+
metricName: string,
|
|
240
|
+
metricHelp: string,
|
|
241
|
+
metricType: string,
|
|
242
|
+
metricValue: number
|
|
243
|
+
) {
|
|
244
|
+
return `# HELP ${metricName} ${metricHelp}.
|
|
245
|
+
# TYPE ${metricName} ${metricType}
|
|
246
|
+
${metricName} ${metricValue}\n`
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export default {
|
|
250
|
+
fetch,
|
|
251
|
+
}
|
|
@@ -12,7 +12,7 @@ import * as exporters from "../view/exporters"
|
|
|
12
12
|
import { apiFileReturn } from "../../../utilities/fileSystem"
|
|
13
13
|
import {
|
|
14
14
|
Operation,
|
|
15
|
-
|
|
15
|
+
UserCtx,
|
|
16
16
|
Row,
|
|
17
17
|
PaginationJson,
|
|
18
18
|
Table,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
SortJson,
|
|
22
22
|
} from "@budibase/types"
|
|
23
23
|
import sdk from "../../../sdk"
|
|
24
|
+
import * as utils from "./utils"
|
|
24
25
|
|
|
25
26
|
const { cleanExportRows } = require("./utils")
|
|
26
27
|
|
|
@@ -49,12 +50,19 @@ export async function handleRequest(
|
|
|
49
50
|
)
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
export async function patch(ctx:
|
|
53
|
+
export async function patch(ctx: UserCtx) {
|
|
53
54
|
const inputs = ctx.request.body
|
|
54
55
|
const tableId = ctx.params.tableId
|
|
55
56
|
const id = inputs._id
|
|
56
57
|
// don't save the ID to db
|
|
57
58
|
delete inputs._id
|
|
59
|
+
const validateResult = await utils.validate({
|
|
60
|
+
row: inputs,
|
|
61
|
+
tableId,
|
|
62
|
+
})
|
|
63
|
+
if (!validateResult.valid) {
|
|
64
|
+
throw { validation: validateResult.errors }
|
|
65
|
+
}
|
|
58
66
|
return handleRequest(Operation.UPDATE, tableId, {
|
|
59
67
|
id: breakRowIdField(id),
|
|
60
68
|
row: inputs,
|
|
@@ -62,16 +70,23 @@ export async function patch(ctx: BBContext) {
|
|
|
62
70
|
})
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
export async function save(ctx:
|
|
73
|
+
export async function save(ctx: UserCtx) {
|
|
66
74
|
const inputs = ctx.request.body
|
|
67
75
|
const tableId = ctx.params.tableId
|
|
76
|
+
const validateResult = await utils.validate({
|
|
77
|
+
row: inputs,
|
|
78
|
+
tableId,
|
|
79
|
+
})
|
|
80
|
+
if (!validateResult.valid) {
|
|
81
|
+
throw { validation: validateResult.errors }
|
|
82
|
+
}
|
|
68
83
|
return handleRequest(Operation.CREATE, tableId, {
|
|
69
84
|
row: inputs,
|
|
70
85
|
includeSqlRelationships: IncludeRelationship.EXCLUDE,
|
|
71
86
|
})
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
export async function fetchView(ctx:
|
|
89
|
+
export async function fetchView(ctx: UserCtx) {
|
|
75
90
|
// there are no views in external datasources, shouldn't ever be called
|
|
76
91
|
// for now just fetch
|
|
77
92
|
const split = ctx.params.viewName.split("all_")
|
|
@@ -79,14 +94,14 @@ export async function fetchView(ctx: BBContext) {
|
|
|
79
94
|
return fetch(ctx)
|
|
80
95
|
}
|
|
81
96
|
|
|
82
|
-
export async function fetch(ctx:
|
|
97
|
+
export async function fetch(ctx: UserCtx) {
|
|
83
98
|
const tableId = ctx.params.tableId
|
|
84
99
|
return handleRequest(Operation.READ, tableId, {
|
|
85
100
|
includeSqlRelationships: IncludeRelationship.INCLUDE,
|
|
86
101
|
})
|
|
87
102
|
}
|
|
88
103
|
|
|
89
|
-
export async function find(ctx:
|
|
104
|
+
export async function find(ctx: UserCtx) {
|
|
90
105
|
const id = ctx.params.rowId
|
|
91
106
|
const tableId = ctx.params.tableId
|
|
92
107
|
const response = (await handleRequest(Operation.READ, tableId, {
|
|
@@ -96,7 +111,7 @@ export async function find(ctx: BBContext) {
|
|
|
96
111
|
return response ? response[0] : response
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
export async function destroy(ctx:
|
|
114
|
+
export async function destroy(ctx: UserCtx) {
|
|
100
115
|
const tableId = ctx.params.tableId
|
|
101
116
|
const id = ctx.request.body._id
|
|
102
117
|
const { row } = (await handleRequest(Operation.DELETE, tableId, {
|
|
@@ -106,7 +121,7 @@ export async function destroy(ctx: BBContext) {
|
|
|
106
121
|
return { response: { ok: true }, row }
|
|
107
122
|
}
|
|
108
123
|
|
|
109
|
-
export async function bulkDestroy(ctx:
|
|
124
|
+
export async function bulkDestroy(ctx: UserCtx) {
|
|
110
125
|
const { rows } = ctx.request.body
|
|
111
126
|
const tableId = ctx.params.tableId
|
|
112
127
|
let promises: Promise<Row[] | { row: Row; table: Table }>[] = []
|
|
@@ -122,7 +137,7 @@ export async function bulkDestroy(ctx: BBContext) {
|
|
|
122
137
|
return { response: { ok: true }, rows: responses.map(resp => resp.row) }
|
|
123
138
|
}
|
|
124
139
|
|
|
125
|
-
export async function search(ctx:
|
|
140
|
+
export async function search(ctx: UserCtx) {
|
|
126
141
|
const tableId = ctx.params.tableId
|
|
127
142
|
const { paginate, query, ...params } = ctx.request.body
|
|
128
143
|
let { bookmark, limit } = params
|
|
@@ -185,12 +200,7 @@ export async function search(ctx: BBContext) {
|
|
|
185
200
|
}
|
|
186
201
|
}
|
|
187
202
|
|
|
188
|
-
export async function
|
|
189
|
-
// can't validate external right now - maybe in future
|
|
190
|
-
return { valid: true }
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export async function exportRows(ctx: BBContext) {
|
|
203
|
+
export async function exportRows(ctx: UserCtx) {
|
|
194
204
|
const { datasourceId, tableName } = breakExternalTableId(ctx.params.tableId)
|
|
195
205
|
const format = ctx.query.format
|
|
196
206
|
const { columns } = ctx.request.body
|
|
@@ -244,7 +254,7 @@ export async function exportRows(ctx: BBContext) {
|
|
|
244
254
|
return apiFileReturn(exporter(headers, exportRows))
|
|
245
255
|
}
|
|
246
256
|
|
|
247
|
-
export async function fetchEnrichedRow(ctx:
|
|
257
|
+
export async function fetchEnrichedRow(ctx: UserCtx) {
|
|
248
258
|
const id = ctx.params.rowId
|
|
249
259
|
const tableId = ctx.params.tableId
|
|
250
260
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
|
@@ -2,6 +2,8 @@ import { quotas } from "@budibase/pro"
|
|
|
2
2
|
import * as internal from "./internal"
|
|
3
3
|
import * as external from "./external"
|
|
4
4
|
import { isExternalTable } from "../../../integrations/utils"
|
|
5
|
+
import { Ctx } from "@budibase/types"
|
|
6
|
+
import * as utils from "./utils"
|
|
5
7
|
|
|
6
8
|
function pickApi(tableId: any) {
|
|
7
9
|
if (isExternalTable(tableId)) {
|
|
@@ -129,9 +131,17 @@ export async function search(ctx: any) {
|
|
|
129
131
|
})
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
export async function validate(ctx:
|
|
134
|
+
export async function validate(ctx: Ctx) {
|
|
133
135
|
const tableId = getTableId(ctx)
|
|
134
|
-
|
|
136
|
+
// external tables are hard to validate currently
|
|
137
|
+
if (isExternalTable(tableId)) {
|
|
138
|
+
ctx.body = { valid: true }
|
|
139
|
+
} else {
|
|
140
|
+
ctx.body = await utils.validate({
|
|
141
|
+
row: ctx.request.body,
|
|
142
|
+
tableId,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
export async function fetchEnrichedRow(ctx: any) {
|
|
@@ -387,13 +387,6 @@ export async function search(ctx: Ctx) {
|
|
|
387
387
|
return response
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
export async function validate(ctx: Ctx) {
|
|
391
|
-
return utils.validate({
|
|
392
|
-
tableId: ctx.params.tableId,
|
|
393
|
-
row: ctx.request.body,
|
|
394
|
-
})
|
|
395
|
-
}
|
|
396
|
-
|
|
397
390
|
export async function exportRows(ctx: Ctx) {
|
|
398
391
|
const db = context.getAppDB()
|
|
399
392
|
const table = await db.get(ctx.params.tableId)
|
|
@@ -4,11 +4,11 @@ import { FieldTypes } from "../../../constants"
|
|
|
4
4
|
import { context } from "@budibase/backend-core"
|
|
5
5
|
import { makeExternalQuery } from "../../../integrations/base/query"
|
|
6
6
|
import { Row, Table } from "@budibase/types"
|
|
7
|
-
const validateJs = require("validate.js")
|
|
8
|
-
const { cloneDeep } = require("lodash/fp")
|
|
9
7
|
import { Format } from "../view/exporters"
|
|
10
8
|
import { Ctx } from "@budibase/types"
|
|
11
9
|
import sdk from "../../../sdk"
|
|
10
|
+
const validateJs = require("validate.js")
|
|
11
|
+
const { cloneDeep } = require("lodash/fp")
|
|
12
12
|
|
|
13
13
|
validateJs.extend(validateJs.validators.datetime, {
|
|
14
14
|
parse: function (value: string) {
|
|
@@ -56,17 +56,17 @@ export async function validate({
|
|
|
56
56
|
}) {
|
|
57
57
|
let fetchedTable: Table
|
|
58
58
|
if (!table) {
|
|
59
|
-
|
|
60
|
-
fetchedTable = await db.get(tableId)
|
|
59
|
+
fetchedTable = await sdk.tables.getTable(tableId)
|
|
61
60
|
} else {
|
|
62
61
|
fetchedTable = table
|
|
63
62
|
}
|
|
64
63
|
const errors: any = {}
|
|
65
64
|
for (let fieldName of Object.keys(fetchedTable.schema)) {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
65
|
+
const column = fetchedTable.schema[fieldName]
|
|
66
|
+
const constraints = cloneDeep(column.constraints)
|
|
67
|
+
const type = column.type
|
|
68
68
|
// formulas shouldn't validated, data will be deleted anyway
|
|
69
|
-
if (type === FieldTypes.FORMULA) {
|
|
69
|
+
if (type === FieldTypes.FORMULA || column.autocolumn) {
|
|
70
70
|
continue
|
|
71
71
|
}
|
|
72
72
|
// special case for options, need to always allow unselected (null)
|