forked from tsai/budibase
22 changed files with 345 additions and 440 deletions
@ -1,172 +0,0 @@ |
|||
import { quotas, StaticQuotaName, QuotaUsageType } from "@budibase/pro" |
|||
const { getUniqueRows } = require("../utilities/usageQuota/rows") |
|||
const { |
|||
isExternalTable, |
|||
isRowId: isExternalRowId, |
|||
} = require("../integrations/utils") |
|||
const { getAppDB } = require("@budibase/backend-core/context") |
|||
|
|||
// currently only counting new writes and deletes
|
|||
const METHOD_MAP: any = { |
|||
POST: 1, |
|||
DELETE: -1, |
|||
} |
|||
|
|||
const DOMAIN_MAP: any = { |
|||
rows: { |
|||
name: StaticQuotaName.ROWS, |
|||
type: QuotaUsageType.STATIC, |
|||
}, |
|||
applications: { |
|||
name: StaticQuotaName.APPS, |
|||
type: QuotaUsageType.STATIC, |
|||
}, |
|||
} |
|||
|
|||
function getQuotaInfo(url: string) { |
|||
for (let domain of Object.keys(DOMAIN_MAP)) { |
|||
if (url.indexOf(domain) !== -1) { |
|||
return DOMAIN_MAP[domain] |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = async (ctx: any, next: any) => { |
|||
if (!quotas.useQuotas()) { |
|||
return next() |
|||
} |
|||
|
|||
let usage = METHOD_MAP[ctx.req.method] |
|||
const quotaInfo = getQuotaInfo(ctx.req.url) |
|||
if (usage == null || quotaInfo == null) { |
|||
return next() |
|||
} |
|||
// post request could be a save of a pre-existing entry
|
|||
if (ctx.request.body && ctx.request.body._id && ctx.request.body._rev) { |
|||
const usageId = ctx.request.body._id |
|||
try { |
|||
if (ctx.appId) { |
|||
const db = getAppDB() |
|||
await db.get(usageId) |
|||
} |
|||
return next() |
|||
} catch (err) { |
|||
if ( |
|||
isExternalTable(usageId) || |
|||
(ctx.request.body.tableId && |
|||
isExternalTable(ctx.request.body.tableId)) || |
|||
isExternalRowId(usageId) |
|||
) { |
|||
return next() |
|||
} else { |
|||
ctx.throw(404, `${usageId} does not exist`) |
|||
} |
|||
} |
|||
} |
|||
try { |
|||
await performRequest(ctx, next, quotaInfo, usage) |
|||
} catch (err) { |
|||
ctx.throw(400, err) |
|||
} |
|||
} |
|||
|
|||
const performRequest = async ( |
|||
ctx: any, |
|||
next: any, |
|||
quotaInfo: any, |
|||
usage: number |
|||
) => { |
|||
const usageContext = { |
|||
skipNext: false, |
|||
skipUsage: false, |
|||
[StaticQuotaName.APPS]: {}, |
|||
} |
|||
|
|||
const quotaName = quotaInfo.name |
|||
|
|||
if (usage === -1) { |
|||
if (PRE_DELETE[quotaName]) { |
|||
await PRE_DELETE[quotaName](ctx, usageContext) |
|||
} |
|||
} else { |
|||
if (PRE_CREATE[quotaName]) { |
|||
await PRE_CREATE[quotaName](ctx, usageContext) |
|||
} |
|||
} |
|||
|
|||
// run the request
|
|||
if (!usageContext.skipNext) { |
|||
await quotas.updateUsage(usage, quotaName, quotaInfo.type, { |
|||
dryRun: true, |
|||
}) |
|||
await next() |
|||
} |
|||
|
|||
if (usage === -1) { |
|||
if (POST_DELETE[quotaName]) { |
|||
await POST_DELETE[quotaName](ctx, usageContext) |
|||
} |
|||
} else { |
|||
if (POST_CREATE[quotaName]) { |
|||
await POST_CREATE[quotaName](ctx) |
|||
} |
|||
} |
|||
|
|||
// update the usage
|
|||
if (!usageContext.skipUsage) { |
|||
await quotas.updateUsage(usage, quotaName, quotaInfo.type) |
|||
} |
|||
} |
|||
|
|||
const appPreDelete = async (ctx: any, usageContext: any) => { |
|||
if (ctx.query.unpublish) { |
|||
// don't run usage decrement for unpublish
|
|||
usageContext.skipUsage = true |
|||
return |
|||
} |
|||
|
|||
// store the row count to delete
|
|||
const rows = await getUniqueRows([ctx.appId]) |
|||
if (rows.length) { |
|||
usageContext[StaticQuotaName.APPS] = { rowCount: rows.length } |
|||
} |
|||
} |
|||
|
|||
const appPostDelete = async (ctx: any, usageContext: any) => { |
|||
// delete the app rows from usage
|
|||
const rowCount = usageContext[StaticQuotaName.APPS].rowCount |
|||
if (rowCount) { |
|||
await quotas.updateUsage( |
|||
-rowCount, |
|||
StaticQuotaName.ROWS, |
|||
QuotaUsageType.STATIC |
|||
) |
|||
} |
|||
} |
|||
|
|||
const appPostCreate = async (ctx: any) => { |
|||
// app import & template creation
|
|||
if (ctx.request.body.useTemplate === "true") { |
|||
const rows = await getUniqueRows([ctx.response.body.appId]) |
|||
const rowCount = rows ? rows.length : 0 |
|||
await quotas.updateUsage( |
|||
rowCount, |
|||
StaticQuotaName.ROWS, |
|||
QuotaUsageType.STATIC |
|||
) |
|||
} |
|||
} |
|||
|
|||
const PRE_DELETE: any = { |
|||
[StaticQuotaName.APPS]: appPreDelete, |
|||
} |
|||
|
|||
const POST_DELETE: any = { |
|||
[StaticQuotaName.APPS]: appPostDelete, |
|||
} |
|||
|
|||
const PRE_CREATE: any = {} |
|||
|
|||
const POST_CREATE: any = { |
|||
[StaticQuotaName.APPS]: appPostCreate, |
|||
} |
|||
@ -1,8 +1,3 @@ |
|||
import { quotas } from "@budibase/pro" |
|||
|
|||
export const runQuotaMigration = async (migration: Function) => { |
|||
if (!quotas.useQuotas()) { |
|||
return |
|||
} |
|||
await migration() |
|||
} |
|||
|
|||
@ -1,3 +1,5 @@ |
|||
declare module "@budibase/backend-core" |
|||
declare module "@budibase/backend-core/tenancy" |
|||
declare module "@budibase/backend-core/db" |
|||
declare module "@budibase/backend-core/context" |
|||
declare module "@budibase/backend-core/cache" |
|||
|
|||
Loading…
Reference in new issue