diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index f2f065476e..a3d0b28ae2 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -230,9 +230,10 @@ export async function fetchAppPackage(ctx: BBContext) { async function performAppCreate(ctx: BBContext) { 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) - const url = sdk.applications.getAppUrl(ctx) + const url = sdk.applications.getAppUrl({ name, url: possibleUrl }) checkAppUrl(ctx, apps, url) const { useTemplate, templateKey, templateString } = ctx.request.body @@ -392,11 +393,12 @@ export async function create(ctx: BBContext) { export async function update(ctx: BBContext) { const apps = (await dbCore.getAllApps({ dev: true })) as App[] // validation - const name = ctx.request.body.name + const name = ctx.request.body.name, + possibleUrl = ctx.request.body.url if (name) { checkAppName(ctx, apps, name, ctx.params.appId) } - const url = sdk.applications.getAppUrl(ctx) + const url = sdk.applications.getAppUrl({ name, url: possibleUrl }) if (url) { checkAppUrl(ctx, apps, url, ctx.params.appId) ctx.request.body.url = url diff --git a/packages/server/src/api/controllers/user.ts b/packages/server/src/api/controllers/user.ts index f1a66f2c19..df64ffc7d0 100644 --- a/packages/server/src/api/controllers/user.ts +++ b/packages/server/src/api/controllers/user.ts @@ -1,12 +1,7 @@ -import { - generateUserMetadataID, - getUserMetadataParams, - generateUserFlagID, -} from "../../db/utils" +import { generateUserMetadataID, generateUserFlagID } from "../../db/utils" import { InternalTables } from "../../db/utils" import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global" import { getFullUser } from "../../utilities/users" -import { isEqual } from "lodash" import { context, constants, @@ -14,59 +9,7 @@ import { db as dbCore, } from "@budibase/backend-core" import { BBContext, User } from "@budibase/types" - -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) -} +import sdk from "../../sdk" export async function syncUser(ctx: BBContext) { let deleting = false, @@ -123,7 +66,7 @@ export async function syncUser(ctx: BBContext) { metadata.roleId = roleId } let combined = !deleting - ? combineMetadataAndUser(user, metadata) + ? sdk.users.combineMetadataAndUser(user, metadata) : { ...metadata, status: constants.UserStatus.INACTIVE, @@ -143,7 +86,7 @@ export async function syncUser(ctx: BBContext) { export async function fetchMetadata(ctx: BBContext) { const global = await getGlobalUsers() - const metadata = await rawMetadata() + const metadata = await sdk.users.rawUserMetadata() const users = [] for (let user of global) { // find the metadata that matches up to the global ID diff --git a/packages/server/src/migrations/functions/appUrls.ts b/packages/server/src/migrations/functions/appUrls.ts index 30ce09e188..be03d3c81e 100644 --- a/packages/server/src/migrations/functions/appUrls.ts +++ b/packages/server/src/migrations/functions/appUrls.ts @@ -20,14 +20,7 @@ export const run = async (appDb: any) => { } if (!metadata.url) { - const context = { - request: { - body: { - name: metadata.name, - }, - }, - } - metadata.url = sdk.applications.getAppUrl(context) + metadata.url = sdk.applications.getAppUrl({ name: metadata.name }) console.log(`Adding url to app: ${metadata.url}`) await appDb.put(metadata) } diff --git a/packages/server/src/sdk/app/applications/general.ts b/packages/server/src/sdk/app/applications/general.ts deleted file mode 100644 index 4de94c1b92..0000000000 --- a/packages/server/src/sdk/app/applications/general.ts +++ /dev/null @@ -1,19 +0,0 @@ -const URL_REGEX_SLASH = /\/|\\/g - -export function getAppUrl(ctx: { - request: { body: { name?: string; url?: string } } -}) { - // construct the url - let url - if (ctx.request.body.url) { - // if the url is provided, use that - 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 as string -} diff --git a/packages/server/src/sdk/app/applications/index.ts b/packages/server/src/sdk/app/applications/index.ts index 17100a08ff..d917225e52 100644 --- a/packages/server/src/sdk/app/applications/index.ts +++ b/packages/server/src/sdk/app/applications/index.ts @@ -1,7 +1,7 @@ import * as sync from "./sync" -import * as general from "./general" +import * as utils from "./utils" export default { ...sync, - ...general, + ...utils, } diff --git a/packages/server/src/sdk/app/applications/sync.ts b/packages/server/src/sdk/app/applications/sync.ts index 71931dde21..fba135880d 100644 --- a/packages/server/src/sdk/app/applications/sync.ts +++ b/packages/server/src/sdk/app/applications/sync.ts @@ -1,6 +1,6 @@ import env from "../../../environment" -import { syncGlobalUsers } from "../../../api/controllers/user" 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) { @@ -41,7 +41,7 @@ export async function syncApp(appId: string) { } // sync the users - await syncGlobalUsers() + await sdk.users.syncGlobalUsers() if (error) { throw error diff --git a/packages/server/src/sdk/app/applications/utils.ts b/packages/server/src/sdk/app/applications/utils.ts new file mode 100644 index 0000000000..e7f4742bee --- /dev/null +++ b/packages/server/src/sdk/app/applications/utils.ts @@ -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 +} diff --git a/packages/server/src/sdk/index.ts b/packages/server/src/sdk/index.ts index b80ded90fa..19df8b4388 100644 --- a/packages/server/src/sdk/index.ts +++ b/packages/server/src/sdk/index.ts @@ -2,12 +2,14 @@ import { default as backups } from "./app/backups" import { default as tables } from "./app/tables" import { default as automations } from "./app/automations" import { default as applications } from "./app/applications" +import { default as users } from "./users" const sdk = { backups, tables, automations, applications, + users, } // default export for TS diff --git a/packages/server/src/sdk/users/index.ts b/packages/server/src/sdk/users/index.ts new file mode 100644 index 0000000000..c8431f7e61 --- /dev/null +++ b/packages/server/src/sdk/users/index.ts @@ -0,0 +1,5 @@ +import * as utils from "./utils" + +export default { + ...utils, +} diff --git a/packages/server/src/sdk/users/utils.ts b/packages/server/src/sdk/users/utils.ts new file mode 100644 index 0000000000..f0e0e67824 --- /dev/null +++ b/packages/server/src/sdk/users/utils.ts @@ -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) +}