Merge branch 'develop' of github.com:Budibase/budibase into cheeks-fixes

This commit is contained in:
Andrew Kingston 2022-12-07 09:54:57 +00:00
commit 75d48774f2
27 changed files with 2384 additions and 405 deletions

View File

@ -1,5 +1,5 @@
{ {
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/backend-core", "name": "@budibase/backend-core",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase backend core libraries used in server and worker", "description": "Budibase backend core libraries used in server and worker",
"main": "dist/src/index.js", "main": "dist/src/index.js",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
@ -20,7 +20,7 @@
"test:watch": "jest --watchAll" "test:watch": "jest --watchAll"
}, },
"dependencies": { "dependencies": {
"@budibase/types": "2.1.43-alpha.8", "@budibase/types": "2.1.43-alpha.10",
"@shopify/jest-koa-mocks": "5.0.1", "@shopify/jest-koa-mocks": "5.0.1",
"@techpass/passport-openidconnect": "0.3.2", "@techpass/passport-openidconnect": "0.3.2",
"aws-sdk": "2.1030.0", "aws-sdk": "2.1030.0",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/bbui", "name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.", "description": "A UI solution used in the different Budibase projects.",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"module": "dist/bbui.es.js", "module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1", "@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2", "@spectrum-css/avatar": "^3.0.2",

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"license": "GPL-3.0", "license": "GPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -71,10 +71,10 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.1.43-alpha.8", "@budibase/bbui": "2.1.43-alpha.10",
"@budibase/client": "2.1.43-alpha.8", "@budibase/client": "2.1.43-alpha.10",
"@budibase/frontend-core": "2.1.43-alpha.8", "@budibase/frontend-core": "2.1.43-alpha.10",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1", "@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1", "@spectrum-css/vars": "^3.0.1",

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js", "main": "src/index.js",
"bin": { "bin": {
@ -26,9 +26,9 @@
"outputPath": "build" "outputPath": "build"
}, },
"dependencies": { "dependencies": {
"@budibase/backend-core": "2.1.43-alpha.8", "@budibase/backend-core": "2.1.43-alpha.10",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@budibase/types": "2.1.43-alpha.8", "@budibase/types": "2.1.43-alpha.10",
"axios": "0.21.2", "axios": "0.21.2",
"chalk": "4.1.0", "chalk": "4.1.0",
"cli-progress": "3.11.2", "cli-progress": "3.11.2",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"license": "MPL-2.0", "license": "MPL-2.0",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.1.43-alpha.8", "@budibase/bbui": "2.1.43-alpha.10",
"@budibase/frontend-core": "2.1.43-alpha.8", "@budibase/frontend-core": "2.1.43-alpha.10",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@spectrum-css/button": "^3.0.3", "@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3", "@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3", "@spectrum-css/divider": "^1.0.3",

View File

@ -1,12 +1,12 @@
{ {
"name": "@budibase/frontend-core", "name": "@budibase/frontend-core",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase frontend core libraries used in builder and client", "description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase", "author": "Budibase",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"dependencies": { "dependencies": {
"@budibase/bbui": "2.1.43-alpha.8", "@budibase/bbui": "2.1.43-alpha.10",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"svelte": "^3.46.2" "svelte": "^3.46.2"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/sdk", "name": "@budibase/sdk",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase Public API SDK", "description": "Budibase Public API SDK",
"author": "Budibase", "author": "Budibase",
"license": "MPL-2.0", "license": "MPL-2.0",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -43,11 +43,11 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@apidevtools/swagger-parser": "10.0.3", "@apidevtools/swagger-parser": "10.0.3",
"@budibase/backend-core": "2.1.43-alpha.8", "@budibase/backend-core": "2.1.43-alpha.10",
"@budibase/client": "2.1.43-alpha.8", "@budibase/client": "2.1.43-alpha.10",
"@budibase/pro": "2.1.43-alpha.8", "@budibase/pro": "2.1.43-alpha.10",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@budibase/types": "2.1.43-alpha.8", "@budibase/types": "2.1.43-alpha.10",
"@bull-board/api": "3.7.0", "@bull-board/api": "3.7.0",
"@bull-board/koa": "3.9.4", "@bull-board/koa": "3.9.4",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",

View File

@ -26,7 +26,6 @@ import {
} from "@budibase/backend-core" } from "@budibase/backend-core"
import { USERS_TABLE_SCHEMA } from "../../constants" import { USERS_TABLE_SCHEMA } from "../../constants"
import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default" import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default"
import { removeAppFromUserRoles } from "../../utilities/workerRequests" import { removeAppFromUserRoles } from "../../utilities/workerRequests"
import { import {
clientLibraryPath, clientLibraryPath,
@ -39,18 +38,22 @@ import {
backupClientLibrary, backupClientLibrary,
revertClientLibrary, revertClientLibrary,
} from "../../utilities/fileSystem/clientLibrary" } from "../../utilities/fileSystem/clientLibrary"
import { syncGlobalUsers } from "./user"
import { cleanupAutomations } from "../../automations/utils" import { cleanupAutomations } from "../../automations/utils"
import { checkAppMetadata } from "../../automations/logging" import { checkAppMetadata } from "../../automations/logging"
import { getUniqueRows } from "../../utilities/usageQuota/rows" import { getUniqueRows } from "../../utilities/usageQuota/rows"
import { quotas, groups } from "@budibase/pro" import { quotas, groups } from "@budibase/pro"
import { App, Layout, Screen, MigrationType } from "@budibase/types" import {
App,
Layout,
Screen,
MigrationType,
BBContext,
Database,
} from "@budibase/types"
import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts" import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts"
import { enrichPluginURLs } from "../../utilities/plugins" import { enrichPluginURLs } from "../../utilities/plugins"
import sdk from "../../sdk" import sdk from "../../sdk"
const URL_REGEX_SLASH = /\/|\\/g
// utility function, need to do away with this // utility function, need to do away with this
async function getLayouts() { async function getLayouts() {
const db = context.getAppDB() const db = context.getAppDB()
@ -74,29 +77,18 @@ async function getScreens() {
).rows.map((row: any) => row.doc) ).rows.map((row: any) => row.doc)
} }
function getUserRoleId(ctx: any) { function getUserRoleId(ctx: BBContext) {
return !ctx.user.role || !ctx.user.role._id return !ctx.user?.role || !ctx.user.role._id
? roles.BUILTIN_ROLE_IDS.PUBLIC ? roles.BUILTIN_ROLE_IDS.PUBLIC
: ctx.user.role._id : ctx.user.role._id
} }
export const getAppUrl = (ctx: any) => { function checkAppUrl(
// construct the url ctx: BBContext,
let url apps: App[],
if (ctx.request.body.url) { url: string,
// if the url is provided, use that currentAppId?: string
url = encodeURI(ctx.request.body.url) ) {
} else if (ctx.request.body.name) {
// otherwise use the name
url = encodeURI(`${ctx.request.body.name}`)
}
if (url) {
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
}
return url
}
const checkAppUrl = (ctx: any, apps: any, url: any, currentAppId?: string) => {
if (currentAppId) { if (currentAppId) {
apps = apps.filter((app: any) => app.appId !== currentAppId) apps = apps.filter((app: any) => app.appId !== currentAppId)
} }
@ -105,12 +97,12 @@ const checkAppUrl = (ctx: any, apps: any, url: any, currentAppId?: string) => {
} }
} }
const checkAppName = ( function checkAppName(
ctx: any, ctx: BBContext,
apps: any, apps: App[],
name: any, name: string,
currentAppId?: string currentAppId?: string
) => { ) {
// TODO: Replace with Joi // TODO: Replace with Joi
if (!name) { if (!name) {
ctx.throw(400, "Name is required") ctx.throw(400, "Name is required")
@ -165,14 +157,14 @@ async function createInstance(template: any, includeSampleData: boolean) {
return { _id: appId } return { _id: appId }
} }
const addDefaultTables = async (db: any) => { async function addDefaultTables(db: Database) {
const defaultDbDocs = buildDefaultDocs() const defaultDbDocs = buildDefaultDocs()
// add in the default db data docs - tables, datasource, rows and links // add in the default db data docs - tables, datasource, rows and links
await db.bulkDocs([...defaultDbDocs]) await db.bulkDocs([...defaultDbDocs])
} }
export const fetch = async (ctx: any) => { export async function fetch(ctx: BBContext) {
const dev = ctx.query && ctx.query.status === AppStatus.DEV const dev = ctx.query && ctx.query.status === AppStatus.DEV
const all = ctx.query && ctx.query.status === AppStatus.ALL const all = ctx.query && ctx.query.status === AppStatus.ALL
const apps = (await dbCore.getAllApps({ dev, all })) as App[] const apps = (await dbCore.getAllApps({ dev, all })) as App[]
@ -197,7 +189,7 @@ export const fetch = async (ctx: any) => {
ctx.body = await checkAppMetadata(apps) ctx.body = await checkAppMetadata(apps)
} }
export const fetchAppDefinition = async (ctx: any) => { export async function fetchAppDefinition(ctx: BBContext) {
const layouts = await getLayouts() const layouts = await getLayouts()
const userRoleId = getUserRoleId(ctx) const userRoleId = getUserRoleId(ctx)
const accessController = new roles.AccessController() const accessController = new roles.AccessController()
@ -212,7 +204,7 @@ export const fetchAppDefinition = async (ctx: any) => {
} }
} }
export const fetchAppPackage = async (ctx: any) => { export async function fetchAppPackage(ctx: BBContext) {
const db = context.getAppDB() const db = context.getAppDB()
let application = await db.get(DocumentType.APP_METADATA) let application = await db.get(DocumentType.APP_METADATA)
const layouts = await getLayouts() const layouts = await getLayouts()
@ -222,7 +214,7 @@ export const fetchAppPackage = async (ctx: any) => {
application.usedPlugins = enrichPluginURLs(application.usedPlugins) application.usedPlugins = enrichPluginURLs(application.usedPlugins)
// Only filter screens if the user is not a builder // Only filter screens if the user is not a builder
if (!(ctx.user.builder && ctx.user.builder.global)) { if (!(ctx.user?.builder && ctx.user.builder.global)) {
const userRoleId = getUserRoleId(ctx) const userRoleId = getUserRoleId(ctx)
const accessController = new roles.AccessController() const accessController = new roles.AccessController()
screens = await accessController.checkScreensAccess(screens, userRoleId) screens = await accessController.checkScreensAccess(screens, userRoleId)
@ -236,11 +228,12 @@ export const fetchAppPackage = async (ctx: any) => {
} }
} }
const performAppCreate = async (ctx: any) => { async function performAppCreate(ctx: BBContext) {
const apps = await dbCore.getAllApps({ dev: true }) const apps = (await dbCore.getAllApps({ dev: true })) as App[]
const name = ctx.request.body.name const name = ctx.request.body.name,
possibleUrl = ctx.request.body.url
checkAppName(ctx, apps, name) checkAppName(ctx, apps, name)
const url = getAppUrl(ctx) const url = sdk.applications.getAppUrl({ name, url: possibleUrl })
checkAppUrl(ctx, apps, url) checkAppUrl(ctx, apps, url)
const { useTemplate, templateKey, templateString } = ctx.request.body const { useTemplate, templateKey, templateString } = ctx.request.body
@ -331,7 +324,7 @@ const performAppCreate = async (ctx: any) => {
return newApplication return newApplication
} }
const creationEvents = async (request: any, app: App) => { async function creationEvents(request: any, app: App) {
let creationFns: ((app: App) => Promise<void>)[] = [] let creationFns: ((app: App) => Promise<void>)[] = []
const body = request.body const body = request.body
@ -356,7 +349,7 @@ const creationEvents = async (request: any, app: App) => {
} }
} }
const appPostCreate = async (ctx: any, app: App) => { async function appPostCreate(ctx: BBContext, app: App) {
const tenantId = tenancy.getTenantId() const tenantId = tenancy.getTenantId()
await migrations.backPopulateMigrations({ await migrations.backPopulateMigrations({
type: MigrationType.APP, type: MigrationType.APP,
@ -377,7 +370,7 @@ const appPostCreate = async (ctx: any, app: App) => {
if (err.code && err.code === errors.codes.USAGE_LIMIT_EXCEEDED) { if (err.code && err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
// this import resulted in row usage exceeding the quota // this import resulted in row usage exceeding the quota
// delete the app // delete the app
// skip pre and post steps as no rows have been added to quotas yet // skip pre- and post-steps as no rows have been added to quotas yet
ctx.params.appId = app.appId ctx.params.appId = app.appId
await destroyApp(ctx) await destroyApp(ctx)
} }
@ -387,7 +380,7 @@ const appPostCreate = async (ctx: any, app: App) => {
} }
} }
export const create = async (ctx: any) => { export async function create(ctx: BBContext) {
const newApplication = await quotas.addApp(() => performAppCreate(ctx)) const newApplication = await quotas.addApp(() => performAppCreate(ctx))
await appPostCreate(ctx, newApplication) await appPostCreate(ctx, newApplication)
await cache.bustCache(cache.CacheKey.CHECKLIST) await cache.bustCache(cache.CacheKey.CHECKLIST)
@ -397,14 +390,15 @@ export const create = async (ctx: any) => {
// This endpoint currently operates as a PATCH rather than a PUT // This endpoint currently operates as a PATCH rather than a PUT
// Thus name and url fields are handled only if present // Thus name and url fields are handled only if present
export const update = async (ctx: any) => { export async function update(ctx: BBContext) {
const apps = await dbCore.getAllApps({ dev: true }) const apps = (await dbCore.getAllApps({ dev: true })) as App[]
// validation // validation
const name = ctx.request.body.name const name = ctx.request.body.name,
possibleUrl = ctx.request.body.url
if (name) { if (name) {
checkAppName(ctx, apps, name, ctx.params.appId) checkAppName(ctx, apps, name, ctx.params.appId)
} }
const url = getAppUrl(ctx) const url = sdk.applications.getAppUrl({ name, url: possibleUrl })
if (url) { if (url) {
checkAppUrl(ctx, apps, url, ctx.params.appId) checkAppUrl(ctx, apps, url, ctx.params.appId)
ctx.request.body.url = url ctx.request.body.url = url
@ -416,7 +410,7 @@ export const update = async (ctx: any) => {
ctx.body = app ctx.body = app
} }
export const updateClient = async (ctx: any) => { export async function updateClient(ctx: BBContext) {
// Get current app version // Get current app version
const db = context.getAppDB() const db = context.getAppDB()
const application = await db.get(DocumentType.APP_METADATA) const application = await db.get(DocumentType.APP_METADATA)
@ -440,7 +434,7 @@ export const updateClient = async (ctx: any) => {
ctx.body = app ctx.body = app
} }
export const revertClient = async (ctx: any) => { export async function revertClient(ctx: BBContext) {
// Check app can be reverted // Check app can be reverted
const db = context.getAppDB() const db = context.getAppDB()
const application = await db.get(DocumentType.APP_METADATA) const application = await db.get(DocumentType.APP_METADATA)
@ -466,12 +460,15 @@ export const revertClient = async (ctx: any) => {
ctx.body = app ctx.body = app
} }
const destroyApp = async (ctx: any) => { async function destroyApp(ctx: BBContext) {
let appId = ctx.params.appId let appId = ctx.params.appId
let isUnpublish = ctx.query && ctx.query.unpublish let isUnpublish = ctx.query && ctx.query.unpublish
if (isUnpublish) { if (isUnpublish) {
appId = dbCore.getProdAppID(appId) appId = dbCore.getProdAppID(appId)
const devAppId = dbCore.getDevAppID(appId)
// sync before removing the published app
await sdk.applications.syncApp(devAppId)
} }
const db = isUnpublish ? context.getProdAppDB() : context.getAppDB() const db = isUnpublish ? context.getProdAppDB() : context.getAppDB()
@ -501,12 +498,12 @@ const destroyApp = async (ctx: any) => {
return result return result
} }
const preDestroyApp = async (ctx: any) => { async function preDestroyApp(ctx: BBContext) {
const { rows } = await getUniqueRows([ctx.params.appId]) const { rows } = await getUniqueRows([ctx.params.appId])
ctx.rowCount = rows.length ctx.rowCount = rows.length
} }
const postDestroyApp = async (ctx: any) => { async function postDestroyApp(ctx: BBContext) {
const rowCount = ctx.rowCount const rowCount = ctx.rowCount
await groups.cleanupApp(ctx.params.appId) await groups.cleanupApp(ctx.params.appId)
if (rowCount) { if (rowCount) {
@ -514,7 +511,7 @@ const postDestroyApp = async (ctx: any) => {
} }
} }
export const destroy = async (ctx: any) => { export async function destroy(ctx: BBContext) {
await preDestroyApp(ctx) await preDestroyApp(ctx)
const result = await destroyApp(ctx) const result = await destroyApp(ctx)
await postDestroyApp(ctx) await postDestroyApp(ctx)
@ -522,62 +519,16 @@ export const destroy = async (ctx: any) => {
ctx.body = result ctx.body = result
} }
export const sync = async (ctx: any, next: any) => { export async function sync(ctx: BBContext) {
if (env.DISABLE_AUTO_PROD_APP_SYNC) {
ctx.status = 200
ctx.body = {
message:
"App sync disabled. You can reenable with the DISABLE_AUTO_PROD_APP_SYNC environment variable.",
}
return next()
}
const appId = ctx.params.appId const appId = ctx.params.appId
if (!dbCore.isDevAppID(appId)) {
ctx.throw(400, "This action cannot be performed for production apps")
}
// replicate prod to dev
const prodAppId = dbCore.getProdAppID(appId)
// specific case, want to make sure setup is skipped
const prodDb = context.getProdAppDB({ skip_setup: true })
const exists = await prodDb.exists()
if (!exists) {
// the database doesn't exist. Don't replicate
ctx.status = 200
ctx.body = {
message: "App sync not required, app not deployed.",
}
return next()
}
const replication = new dbCore.Replication({
source: prodAppId,
target: appId,
})
let error
try { try {
await replication.replicate(replication.appReplicateOpts()) ctx.body = await sdk.applications.syncApp(appId)
} catch (err) { } catch (err: any) {
error = err ctx.throw(err.status || 400, err.message)
} finally {
await replication.close()
}
// sync the users
await syncGlobalUsers()
if (error) {
ctx.throw(400, error)
} else {
ctx.body = {
message: "App sync completed successfully.",
}
} }
} }
export const updateAppPackage = async (appPackage: any, appId: any) => { export async function updateAppPackage(appPackage: any, appId: any) {
return context.doInAppContext(appId, async () => { return context.doInAppContext(appId, async () => {
const db = context.getAppDB() const db = context.getAppDB()
const application = await db.get(DocumentType.APP_METADATA) const application = await db.get(DocumentType.APP_METADATA)
@ -598,7 +549,7 @@ export const updateAppPackage = async (appPackage: any, appId: any) => {
}) })
} }
const migrateAppNavigation = async () => { async function migrateAppNavigation() {
const db = context.getAppDB() const db = context.getAppDB()
const existing: App = await db.get(DocumentType.APP_METADATA) const existing: App = await db.get(DocumentType.APP_METADATA)
const layouts: Layout[] = await getLayouts() const layouts: Layout[] = await getLayouts()

View File

@ -22,6 +22,7 @@ async function createApp(appName: string, appDirectory: string) {
}, },
}, },
} }
// @ts-ignore
return create(ctx) return create(ctx)
} }

View File

@ -1,12 +1,7 @@
import { import { generateUserMetadataID, generateUserFlagID } from "../../db/utils"
generateUserMetadataID,
getUserMetadataParams,
generateUserFlagID,
} from "../../db/utils"
import { InternalTables } from "../../db/utils" import { InternalTables } from "../../db/utils"
import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global" import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global"
import { getFullUser } from "../../utilities/users" import { getFullUser } from "../../utilities/users"
import { isEqual } from "lodash"
import { import {
context, context,
constants, constants,
@ -14,59 +9,7 @@ import {
db as dbCore, db as dbCore,
} from "@budibase/backend-core" } from "@budibase/backend-core"
import { BBContext, User } from "@budibase/types" import { BBContext, User } from "@budibase/types"
import sdk from "../../sdk"
async function rawMetadata() {
const db = context.getAppDB()
return (
await db.allDocs(
getUserMetadataParams(null, {
include_docs: true,
})
)
).rows.map(row => row.doc)
}
function combineMetadataAndUser(user: any, metadata: any) {
// skip users with no access
if (user.roleId === rolesCore.BUILTIN_ROLE_IDS.PUBLIC) {
return null
}
delete user._rev
const metadataId = generateUserMetadataID(user._id)
const newDoc = {
...user,
_id: metadataId,
tableId: InternalTables.USER_METADATA,
}
const found = Array.isArray(metadata)
? metadata.find(doc => doc._id === metadataId)
: metadata
// copy rev over for the purposes of equality check
if (found) {
newDoc._rev = found._rev
}
if (found == null || !isEqual(newDoc, found)) {
return {
...found,
...newDoc,
}
}
return null
}
export async function syncGlobalUsers() {
// sync user metadata
const db = context.getAppDB()
const [users, metadata] = await Promise.all([getGlobalUsers(), rawMetadata()])
const toWrite = []
for (let user of users) {
const combined = await combineMetadataAndUser(user, metadata)
if (combined) {
toWrite.push(combined)
}
}
await db.bulkDocs(toWrite)
}
export async function syncUser(ctx: BBContext) { export async function syncUser(ctx: BBContext) {
let deleting = false, let deleting = false,
@ -123,7 +66,7 @@ export async function syncUser(ctx: BBContext) {
metadata.roleId = roleId metadata.roleId = roleId
} }
let combined = !deleting let combined = !deleting
? combineMetadataAndUser(user, metadata) ? sdk.users.combineMetadataAndUser(user, metadata)
: { : {
...metadata, ...metadata,
status: constants.UserStatus.INACTIVE, status: constants.UserStatus.INACTIVE,
@ -143,7 +86,7 @@ export async function syncUser(ctx: BBContext) {
export async function fetchMetadata(ctx: BBContext) { export async function fetchMetadata(ctx: BBContext) {
const global = await getGlobalUsers() const global = await getGlobalUsers()
const metadata = await rawMetadata() const metadata = await sdk.users.rawUserMetadata()
const users = [] const users = []
for (let user of global) { for (let user of global) {
// find the metadata that matches up to the global ID // find the metadata that matches up to the global ID

View File

@ -17,7 +17,6 @@ const {
checkBuilderEndpoint, checkBuilderEndpoint,
} = require("./utilities/TestFunctions") } = require("./utilities/TestFunctions")
const setup = require("./utilities") const setup = require("./utilities")
const { basicScreen, basicLayout } = setup.structures
const { AppStatus } = require("../../../db/utils") const { AppStatus } = require("../../../db/utils")
const { events } = require("@budibase/backend-core") const { events } = require("@budibase/backend-core")

View File

@ -1,5 +1,5 @@
import { db as dbCore } from "@budibase/backend-core" import { db as dbCore } from "@budibase/backend-core"
import { getAppUrl } from "../../api/controllers/application" import sdk from "../../sdk"
/** /**
* Date: * Date:
@ -20,14 +20,7 @@ export const run = async (appDb: any) => {
} }
if (!metadata.url) { if (!metadata.url) {
const context = { metadata.url = sdk.applications.getAppUrl({ name: metadata.name })
request: {
body: {
name: metadata.name,
},
},
}
metadata.url = getAppUrl(context)
console.log(`Adding url to app: ${metadata.url}`) console.log(`Adding url to app: ${metadata.url}`)
await appDb.put(metadata) await appDb.put(metadata)
} }

View File

@ -0,0 +1,7 @@
import * as sync from "./sync"
import * as utils from "./utils"
export default {
...sync,
...utils,
}

View File

@ -0,0 +1,53 @@
import env from "../../../environment"
import { db as dbCore, context } from "@budibase/backend-core"
import sdk from "../../"
export async function syncApp(appId: string) {
if (env.DISABLE_AUTO_PROD_APP_SYNC) {
return {
message:
"App sync disabled. You can reenable with the DISABLE_AUTO_PROD_APP_SYNC environment variable.",
}
}
if (dbCore.isProdAppID(appId)) {
throw new Error("This action cannot be performed for production apps")
}
// replicate prod to dev
const prodAppId = dbCore.getProdAppID(appId)
// specific case, want to make sure setup is skipped
const prodDb = context.getProdAppDB({ skip_setup: true })
const exists = await prodDb.exists()
if (!exists) {
// the database doesn't exist. Don't replicate
return {
message: "App sync not required, app not deployed.",
}
}
const replication = new dbCore.Replication({
source: prodAppId,
target: appId,
})
let error
try {
await replication.replicate(replication.appReplicateOpts())
} catch (err) {
error = err
} finally {
await replication.close()
}
// sync the users
await sdk.users.syncGlobalUsers()
if (error) {
throw error
} else {
return {
message: "App sync completed successfully.",
}
}
}

View File

@ -0,0 +1,17 @@
const URL_REGEX_SLASH = /\/|\\/g
export function getAppUrl(opts?: { name?: string; url?: string }) {
// construct the url
let url
if (opts?.url) {
// if the url is provided, use that
url = encodeURI(opts?.url)
} else if (opts?.name) {
// otherwise use the name
url = encodeURI(`${opts?.name}`)
}
if (url) {
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
}
return url as string
}

View File

@ -1,15 +1,16 @@
import { default as backups } from "./app/backups" import { default as backups } from "./app/backups"
import { default as tables } from "./app/tables" import { default as tables } from "./app/tables"
import { default as automations } from "./app/automations" import { default as automations } from "./app/automations"
import { default as applications } from "./app/applications"
import { default as users } from "./users"
const sdk = { const sdk = {
backups, backups,
tables, tables,
automations, automations,
applications,
users,
} }
// default export for TS // default export for TS
export default sdk export default sdk
// default export for JS
module.exports = sdk

View File

@ -0,0 +1,5 @@
import * as utils from "./utils"
export default {
...utils,
}

View File

@ -0,0 +1,64 @@
import { getGlobalUsers } from "../../utilities/global"
import { context, roles as rolesCore } from "@budibase/backend-core"
import {
generateUserMetadataID,
getUserMetadataParams,
InternalTables,
} from "../../db/utils"
import { isEqual } from "lodash"
export function combineMetadataAndUser(user: any, metadata: any) {
// skip users with no access
if (user.roleId === rolesCore.BUILTIN_ROLE_IDS.PUBLIC) {
return null
}
delete user._rev
const metadataId = generateUserMetadataID(user._id)
const newDoc = {
...user,
_id: metadataId,
tableId: InternalTables.USER_METADATA,
}
const found = Array.isArray(metadata)
? metadata.find(doc => doc._id === metadataId)
: metadata
// copy rev over for the purposes of equality check
if (found) {
newDoc._rev = found._rev
}
if (found == null || !isEqual(newDoc, found)) {
return {
...found,
...newDoc,
}
}
return null
}
export async function rawUserMetadata() {
const db = context.getAppDB()
return (
await db.allDocs(
getUserMetadataParams(null, {
include_docs: true,
})
)
).rows.map(row => row.doc)
}
export async function syncGlobalUsers() {
// sync user metadata
const db = context.getAppDB()
const [users, metadata] = await Promise.all([
getGlobalUsers(),
rawUserMetadata(),
])
const toWrite = []
for (let user of users) {
const combined = await combineMetadataAndUser(user, metadata)
if (combined) {
toWrite.push(combined)
}
}
await db.bulkDocs(toWrite)
}

View File

@ -1273,12 +1273,12 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/backend-core@2.1.43-alpha.8": "@budibase/backend-core@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.43-alpha.8.tgz#fca647e547ee9c4886ddc83275059fad6b7547ea" resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.43-alpha.10.tgz#573647b851993734d83ce201c44eb4c3df2b8141"
integrity sha512-P3ckwz/vbjnoe5lxe+Dq0pEmIleBjxC8CXkxPGQLZv7DiT6y3Cqdmyk6inhH0+GbxX0VReLoQWjo7EVPDrKP3g== integrity sha512-1YOwm0n1gydvtqas7xW7oje97LiYxCZ0jGIMoxXk8AK94iXAYW/UYEcc/BdOnEvK0Zz4KEfvZ8tgAvq4VM83uQ==
dependencies: dependencies:
"@budibase/types" "2.1.43-alpha.8" "@budibase/types" "2.1.43-alpha.10"
"@shopify/jest-koa-mocks" "5.0.1" "@shopify/jest-koa-mocks" "5.0.1"
"@techpass/passport-openidconnect" "0.3.2" "@techpass/passport-openidconnect" "0.3.2"
aws-sdk "2.1030.0" aws-sdk "2.1030.0"
@ -1360,13 +1360,13 @@
svelte-flatpickr "^3.2.3" svelte-flatpickr "^3.2.3"
svelte-portal "^1.0.0" svelte-portal "^1.0.0"
"@budibase/pro@2.1.43-alpha.8": "@budibase/pro@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.43-alpha.8.tgz#fbbc7f0190937f0729059ed85ba270bdcd0c59e9" resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.43-alpha.10.tgz#300ba146e2715b9b3d36f4febcde030f01760347"
integrity sha512-EfzJVkHK/AekXIgNC33le78zWTufusQMipzAxy7HJXAS4KhVXtt5NfPCZUEVtqP9Zbz4Gn9+SFIQtWjQxa4+Jg== integrity sha512-q9bwYw3xcDD08z9OZVHfqiBKNGjdDQ+c+SEYQRlNrvF9EbGc4WFiPzKDJrNlVSQF+/+oBHxGo6J9mFqrL66sdA==
dependencies: dependencies:
"@budibase/backend-core" "2.1.43-alpha.8" "@budibase/backend-core" "2.1.43-alpha.10"
"@budibase/types" "2.1.43-alpha.8" "@budibase/types" "2.1.43-alpha.10"
"@koa/router" "8.0.8" "@koa/router" "8.0.8"
bull "4.10.1" bull "4.10.1"
joi "17.6.0" joi "17.6.0"
@ -1390,10 +1390,10 @@
svelte-apexcharts "^1.0.2" svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0" svelte-flatpickr "^3.1.0"
"@budibase/types@2.1.43-alpha.8": "@budibase/types@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.43-alpha.8.tgz#0fb272a2de0438411727136c57e3d64ba7a2a728" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.43-alpha.10.tgz#0ee0766d07126a36913836de94d8fcebc77aead3"
integrity sha512-1Asklst/6ZoZHbfbaDknUSbzFBev3DhvlYMKJ+s8dn2vzXn17SkeLeO+x0GRVlrszKs4cSP6yE+qsu9a2pp0kg== integrity sha512-APp/srnTGZ1nIgCuOMsm2rEimMjKzKHZYd1QkuRq13dFcuwTG+Gr/soITTWurczAbS9jTo3MfZh859s1uv2e3g==
"@bull-board/api@3.7.0": "@bull-board/api@3.7.0":
version "3.7.0" version "3.7.0"

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/string-templates", "name": "@budibase/string-templates",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Handlebars wrapper for Budibase templating.", "description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs", "main": "src/index.cjs",
"module": "dist/bundle.mjs", "module": "dist/bundle.mjs",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/types", "name": "@budibase/types",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase types", "description": "Budibase types",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/worker", "name": "@budibase/worker",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "2.1.43-alpha.8", "version": "2.1.43-alpha.10",
"description": "Budibase background service", "description": "Budibase background service",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -36,10 +36,10 @@
"author": "Budibase", "author": "Budibase",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@budibase/backend-core": "2.1.43-alpha.8", "@budibase/backend-core": "2.1.43-alpha.10",
"@budibase/pro": "2.1.43-alpha.8", "@budibase/pro": "2.1.43-alpha.10",
"@budibase/string-templates": "2.1.43-alpha.8", "@budibase/string-templates": "2.1.43-alpha.10",
"@budibase/types": "2.1.43-alpha.8", "@budibase/types": "2.1.43-alpha.10",
"@koa/router": "8.0.8", "@koa/router": "8.0.8",
"@sentry/node": "6.17.7", "@sentry/node": "6.17.7",
"@techpass/passport-openidconnect": "0.3.2", "@techpass/passport-openidconnect": "0.3.2",

View File

@ -470,12 +470,12 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/backend-core@2.1.43-alpha.8": "@budibase/backend-core@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.43-alpha.8.tgz#fca647e547ee9c4886ddc83275059fad6b7547ea" resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.43-alpha.10.tgz#573647b851993734d83ce201c44eb4c3df2b8141"
integrity sha512-P3ckwz/vbjnoe5lxe+Dq0pEmIleBjxC8CXkxPGQLZv7DiT6y3Cqdmyk6inhH0+GbxX0VReLoQWjo7EVPDrKP3g== integrity sha512-1YOwm0n1gydvtqas7xW7oje97LiYxCZ0jGIMoxXk8AK94iXAYW/UYEcc/BdOnEvK0Zz4KEfvZ8tgAvq4VM83uQ==
dependencies: dependencies:
"@budibase/types" "2.1.43-alpha.8" "@budibase/types" "2.1.43-alpha.10"
"@shopify/jest-koa-mocks" "5.0.1" "@shopify/jest-koa-mocks" "5.0.1"
"@techpass/passport-openidconnect" "0.3.2" "@techpass/passport-openidconnect" "0.3.2"
aws-sdk "2.1030.0" aws-sdk "2.1030.0"
@ -507,22 +507,22 @@
uuid "8.3.2" uuid "8.3.2"
zlib "1.0.5" zlib "1.0.5"
"@budibase/pro@2.1.43-alpha.8": "@budibase/pro@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.43-alpha.8.tgz#fbbc7f0190937f0729059ed85ba270bdcd0c59e9" resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.43-alpha.10.tgz#300ba146e2715b9b3d36f4febcde030f01760347"
integrity sha512-EfzJVkHK/AekXIgNC33le78zWTufusQMipzAxy7HJXAS4KhVXtt5NfPCZUEVtqP9Zbz4Gn9+SFIQtWjQxa4+Jg== integrity sha512-q9bwYw3xcDD08z9OZVHfqiBKNGjdDQ+c+SEYQRlNrvF9EbGc4WFiPzKDJrNlVSQF+/+oBHxGo6J9mFqrL66sdA==
dependencies: dependencies:
"@budibase/backend-core" "2.1.43-alpha.8" "@budibase/backend-core" "2.1.43-alpha.10"
"@budibase/types" "2.1.43-alpha.8" "@budibase/types" "2.1.43-alpha.10"
"@koa/router" "8.0.8" "@koa/router" "8.0.8"
bull "4.10.1" bull "4.10.1"
joi "17.6.0" joi "17.6.0"
node-fetch "^2.6.1" node-fetch "^2.6.1"
"@budibase/types@2.1.43-alpha.8": "@budibase/types@2.1.43-alpha.10":
version "2.1.43-alpha.8" version "2.1.43-alpha.10"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.43-alpha.8.tgz#0fb272a2de0438411727136c57e3d64ba7a2a728" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.43-alpha.10.tgz#0ee0766d07126a36913836de94d8fcebc77aead3"
integrity sha512-1Asklst/6ZoZHbfbaDknUSbzFBev3DhvlYMKJ+s8dn2vzXn17SkeLeO+x0GRVlrszKs4cSP6yE+qsu9a2pp0kg== integrity sha512-APp/srnTGZ1nIgCuOMsm2rEimMjKzKHZYd1QkuRq13dFcuwTG+Gr/soITTWurczAbS9jTo3MfZh859s1uv2e3g==
"@cspotcode/source-map-support@^0.8.0": "@cspotcode/source-map-support@^0.8.0":
version "0.8.1" version "0.8.1"