diff --git a/packages/server/src/api/controllers/user.ts b/packages/server/src/api/controllers/user.ts index d8c5c5c679..bdbb1c7f93 100644 --- a/packages/server/src/api/controllers/user.ts +++ b/packages/server/src/api/controllers/user.ts @@ -4,19 +4,21 @@ import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global" import { getFullUser } from "../../utilities/users" import { context, - constants, roles as rolesCore, db as dbCore, } from "@budibase/backend-core" -import { BBContext, Ctx, User } from "@budibase/types" +import { BBContext, Ctx, isUser, User } from "@budibase/types" import sdk from "../../sdk" -export async function syncUser(ctx: BBContext) { +export async function syncUser(ctx: Ctx) { let deleting = false, user: User | any const userId = ctx.params.id + + const previousUser = ctx.request.body?.previousUser + try { - user = await getRawGlobalUser(userId) + user = (await getRawGlobalUser(userId)) as User } catch (err: any) { if (err && err.status === 404) { user = {} @@ -25,6 +27,11 @@ export async function syncUser(ctx: BBContext) { throw err } } + + let previousApps = isUser(previousUser) + ? Object.keys(previousUser.roles).map(appId => appId) + : [] + const roles = deleting ? {} : user.roles // remove props which aren't useful to metadata delete user.password @@ -40,8 +47,9 @@ export async function syncUser(ctx: BBContext) { .filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC) .map(([appId]) => appId) } - for (let prodAppId of prodAppIds) { + for (let prodAppId of new Set([...prodAppIds, ...previousApps])) { const roleId = roles[prodAppId] + const deleteFromApp = !roleId const devAppId = dbCore.getDevelopmentAppID(prodAppId) for (let appId of [prodAppId, devAppId]) { if (!(await dbCore.dbExists(appId))) { @@ -54,24 +62,24 @@ export async function syncUser(ctx: BBContext) { try { metadata = await db.get(metadataId) } catch (err) { - if (deleting) { + if (deleteFromApp) { return } metadata = { tableId: InternalTables.USER_METADATA, } } + + if (deleteFromApp) { + await db.remove(metadata) + return + } + // assign the roleId for the metadata doc if (roleId) { metadata.roleId = roleId } - let combined = !deleting - ? sdk.users.combineMetadataAndUser(user, metadata) - : { - ...metadata, - status: constants.UserStatus.INACTIVE, - metadata: rolesCore.BUILTIN_ROLE_IDS.PUBLIC, - } + let combined = sdk.users.combineMetadataAndUser(user, metadata) // if its null then there was no updates required if (combined) { await db.put(combined) @@ -173,30 +181,3 @@ export async function getFlags(ctx: BBContext) { } ctx.body = doc } - -export async function removeUserFromApp(ctx: Ctx) { - const { id: userId, prodAppId } = ctx.params - - const devAppId = dbCore.getDevelopmentAppID(prodAppId) - for (let appId of [prodAppId, devAppId]) { - if (!(await dbCore.dbExists(appId))) { - continue - } - await context.doInAppContext(appId, async () => { - const db = context.getAppDB() - const metadataId = generateUserMetadataID(userId) - let metadata - try { - metadata = await db.get(metadataId) - } catch (err) { - console.warn(`User cannot be found in the app`, { userId, appId }) - return - } - - await db.remove(metadata) - }) - } - ctx.body = { - message: `User ${userId} deleted from ${prodAppId} and ${devAppId}.`, - } -} diff --git a/packages/server/src/api/routes/user.ts b/packages/server/src/api/routes/user.ts index 556954fd77..14deb111e6 100644 --- a/packages/server/src/api/routes/user.ts +++ b/packages/server/src/api/routes/user.ts @@ -47,10 +47,5 @@ router authorized(PermissionType.USER, PermissionLevel.READ), controller.getFlags ) - .delete( - "/api/users/metadata/:id/app/:prodAppId", - authorized(PermissionType.USER, PermissionLevel.WRITE), - controller.removeUserFromApp - ) export default router diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index ee83969a52..5787318680 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -70,6 +70,6 @@ export interface AdminUser extends User { } } -export function isUser(user: User | ThirdPartyUser): user is User { +export function isUser(user: any): user is User { return !!(user as User).roles } diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 209ba4d41c..7132c886e6 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -258,17 +258,6 @@ export const save = async ( } } - let appsToRemove: string[] = [] - if (dbUser && isUser(user)) { - const newRoles = Object.keys(user.roles) - const existingRoles = Object.keys(dbUser.roles) - - appsToRemove = existingRoles.filter(r => !newRoles.includes(r)) - if (appsToRemove.length) { - console.log("Deleting access to apps", { appsToRemove }) - } - } - try { // save the user to db let response = await db.put(builtUser) @@ -278,12 +267,8 @@ export const save = async ( await addTenant(tenantId, _id, email) await cache.user.invalidateUser(response.id) - for (const appId of appsToRemove) { - await apps.removeUserFromApp(_id, appId) - } - // let server know to sync user - await apps.syncUserInApps(_id) + await apps.syncUserInApps(_id, dbUser) await Promise.all(groupPromises) diff --git a/packages/worker/src/utilities/appService.ts b/packages/worker/src/utilities/appService.ts index 95a90aebc0..7c725d0a85 100644 --- a/packages/worker/src/utilities/appService.ts +++ b/packages/worker/src/utilities/appService.ts @@ -2,6 +2,7 @@ import fetch from "node-fetch" import { constants, tenancy } from "@budibase/backend-core" import { checkSlashesInUrl } from "../utilities" import env from "../environment" +import { User } from "@budibase/types" async function makeAppRequest(url: string, method: string, body: any) { if (env.isTest()) { @@ -20,24 +21,13 @@ async function makeAppRequest(url: string, method: string, body: any) { return fetch(checkSlashesInUrl(env.APPS_URL + url), request) } -export async function syncUserInApps(userId: string) { +export async function syncUserInApps(userId: string, previousUser?: User) { const response = await makeAppRequest( `/api/users/metadata/sync/${userId}`, "POST", - {} + { previousUser } ) if (response && response.status !== 200) { throw "Unable to sync user." } } - -export async function removeUserFromApp(userId: string, appId: string) { - const response = await makeAppRequest( - `/api/users/metadata/${userId}/app/${appId}`, - "DELETE", - undefined - ) - if (response && response.status !== 200) { - throw "Unable to delete user from app." - } -}