2022-11-16 18:24:13 +01:00
|
|
|
import {
|
|
|
|
APP_DEV_PREFIX,
|
|
|
|
DocumentType,
|
|
|
|
getGlobalIDFromUserMetadataID,
|
|
|
|
} from "../db/utils"
|
|
|
|
import {
|
2021-05-21 14:07:10 +02:00
|
|
|
doesUserHaveLock,
|
|
|
|
updateLock,
|
|
|
|
checkDebounce,
|
|
|
|
setDebounce,
|
2022-11-16 18:24:13 +01:00
|
|
|
} from "../utilities/redis"
|
2022-11-17 15:35:03 +01:00
|
|
|
import { db as dbCore, cache, permissions } from "@budibase/backend-core"
|
|
|
|
import { BBContext, Database } from "@budibase/types"
|
2021-05-21 14:07:10 +02:00
|
|
|
|
2021-05-21 16:14:35 +02:00
|
|
|
const DEBOUNCE_TIME_SEC = 30
|
2021-05-21 14:07:10 +02:00
|
|
|
|
|
|
|
/************************************************** *
|
|
|
|
* This middleware has been broken out of the *
|
|
|
|
* "authorized" middleware as it had nothing to do *
|
|
|
|
* with authorization, but requires the perms *
|
|
|
|
* imparted by it. This middleware shouldn't *
|
|
|
|
* be called directly, it should always be called *
|
|
|
|
* through the authorized middleware *
|
|
|
|
****************************************************/
|
|
|
|
|
2022-11-16 18:24:13 +01:00
|
|
|
async function checkDevAppLocks(ctx: BBContext) {
|
2021-05-21 14:07:10 +02:00
|
|
|
const appId = ctx.appId
|
|
|
|
|
|
|
|
// if any public usage, don't proceed
|
2022-11-16 18:24:13 +01:00
|
|
|
if (!ctx.user?._id && !ctx.user?.userId) {
|
2021-05-21 14:07:10 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// not a development app, don't need to do anything
|
|
|
|
if (!appId || !appId.startsWith(APP_DEV_PREFIX)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (!(await doesUserHaveLock(appId, ctx.user))) {
|
2021-10-06 17:27:46 +02:00
|
|
|
ctx.throw(400, "User does not hold app lock.")
|
2021-05-21 14:07:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// they do have lock, update it
|
|
|
|
await updateLock(appId, ctx.user)
|
|
|
|
}
|
|
|
|
|
2022-11-16 18:24:13 +01:00
|
|
|
async function updateAppUpdatedAt(ctx: BBContext) {
|
2021-05-21 14:07:10 +02:00
|
|
|
const appId = ctx.appId
|
|
|
|
// if debouncing skip this update
|
|
|
|
// get methods also aren't updating
|
2021-05-21 16:03:28 +02:00
|
|
|
if (ctx.method === "GET" || (await checkDebounce(appId))) {
|
2021-05-21 14:07:10 +02:00
|
|
|
return
|
|
|
|
}
|
2022-11-17 15:35:03 +01:00
|
|
|
await dbCore.doWithDB(appId, async (db: Database) => {
|
2022-08-11 14:50:05 +02:00
|
|
|
const metadata = await db.get(DocumentType.APP_METADATA)
|
2022-04-19 20:42:52 +02:00
|
|
|
metadata.updatedAt = new Date().toISOString()
|
2022-05-05 13:52:17 +02:00
|
|
|
|
2022-11-16 18:24:13 +01:00
|
|
|
metadata.updatedBy = getGlobalIDFromUserMetadataID(ctx.user?.userId!)
|
2022-05-05 13:52:17 +02:00
|
|
|
|
2022-04-19 20:42:52 +02:00
|
|
|
const response = await db.put(metadata)
|
|
|
|
metadata._rev = response.rev
|
2022-11-16 18:24:13 +01:00
|
|
|
await cache.app.invalidateAppMetadata(appId, metadata)
|
2022-04-19 20:42:52 +02:00
|
|
|
// set a new debounce record with a short TTL
|
|
|
|
await setDebounce(appId, DEBOUNCE_TIME_SEC)
|
|
|
|
})
|
2021-05-21 14:07:10 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 10:37:37 +01:00
|
|
|
export default async function builder(ctx: BBContext, permType: string) {
|
2021-05-21 14:07:10 +02:00
|
|
|
const appId = ctx.appId
|
|
|
|
// this only functions within an app context
|
|
|
|
if (!appId) {
|
|
|
|
return
|
|
|
|
}
|
2022-11-17 15:59:18 +01:00
|
|
|
const isBuilderApi = permType === permissions.PermissionType.BUILDER
|
2021-05-21 14:07:10 +02:00
|
|
|
const referer = ctx.headers["referer"]
|
2022-05-05 13:52:17 +02:00
|
|
|
|
|
|
|
const overviewPath = "/builder/portal/overview/"
|
|
|
|
const overviewContext = !referer ? false : referer.includes(overviewPath)
|
|
|
|
if (overviewContext) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const hasAppId = !referer ? false : referer.includes(appId)
|
|
|
|
const editingApp = referer ? hasAppId : false
|
2021-05-21 14:07:10 +02:00
|
|
|
// check this is a builder call and editing
|
|
|
|
if (!isBuilderApi || !editingApp) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// check locks
|
|
|
|
await checkDevAppLocks(ctx)
|
|
|
|
// set updated at time on app
|
|
|
|
await updateAppUpdatedAt(ctx)
|
2021-05-21 15:49:59 +02:00
|
|
|
}
|