Merge pull request #9337 from Budibase/bug/#7220-removing-user-from-auth-does-not-remove-from-app
Bug - #7220 removing user from auth does not remove from app
This commit is contained in:
commit
70a01c48f1
|
@ -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, User } from "@budibase/types"
|
||||
import { BBContext, Ctx, SyncUserRequest, User } from "@budibase/types"
|
||||
import sdk from "../../sdk"
|
||||
|
||||
export async function syncUser(ctx: BBContext) {
|
||||
export async function syncUser(ctx: Ctx<SyncUserRequest>) {
|
||||
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 = 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)
|
||||
|
|
|
@ -171,9 +171,28 @@ describe("/users", () => {
|
|||
.expect("Content-Type", /json/)
|
||||
expect(res.body.message).toEqual('User synced.')
|
||||
})
|
||||
|
||||
|
||||
it("should sync the user when a previous user is specified", async () => {
|
||||
const app1 = await config.createApp('App 1')
|
||||
const app2 = await config.createApp('App 2')
|
||||
|
||||
let user = await config.createUser(
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
true,
|
||||
{ [app1.appId]: 'ADMIN' })
|
||||
let res = await request
|
||||
.post(`/api/users/metadata/sync/${user._id}`)
|
||||
.set(config.defaultHeaders())
|
||||
.send({ previousUser: { ...user, roles: { ...user.roles, [app2.appId]: 'BASIC' } } })
|
||||
.expect(200)
|
||||
.expect("Content-Type", /json/)
|
||||
|
||||
expect(res.body.message).toEqual('User synced.')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
|
|
@ -25,6 +25,7 @@ export default async (ctx: BBContext, next: any) => {
|
|||
if (!appCookie && !requestAppId) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// check the app exists referenced in cookie
|
||||
if (appCookie) {
|
||||
const appId = appCookie.appId
|
||||
|
@ -51,7 +52,7 @@ export default async (ctx: BBContext, next: any) => {
|
|||
|
||||
let appId: string | undefined,
|
||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
if (!ctx.user) {
|
||||
if (!ctx.user?._id) {
|
||||
// not logged in, try to set a cookie for public apps
|
||||
appId = requestAppId
|
||||
} else if (requestAppId != null) {
|
||||
|
@ -96,7 +97,7 @@ export default async (ctx: BBContext, next: any) => {
|
|||
// need to judge this only based on the request app ID,
|
||||
if (
|
||||
env.MULTI_TENANCY &&
|
||||
ctx.user &&
|
||||
ctx.user?._id &&
|
||||
requestAppId &&
|
||||
!tenancy.isUserInAppTenant(requestAppId, ctx.user)
|
||||
) {
|
||||
|
|
|
@ -57,3 +57,7 @@ export interface CreateAdminUserRequest {
|
|||
password: string
|
||||
tenantId: string
|
||||
}
|
||||
|
||||
export interface SyncUserRequest {
|
||||
previousUser?: User
|
||||
}
|
||||
|
|
|
@ -69,3 +69,7 @@ export interface AdminUser extends User {
|
|||
global: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export function isUser(user: object): user is User {
|
||||
return !!(user as User).roles
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export interface UserCtx<RequestBody = any, ResponseBody = any>
|
|||
}
|
||||
|
||||
/**
|
||||
* Deprecated: Use UserCtx / Ctx appropriately
|
||||
* @deprecated: Use UserCtx / Ctx appropriately
|
||||
* Authenticated context.
|
||||
*/
|
||||
export interface BBContext extends Ctx {
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
SearchUsersRequest,
|
||||
User,
|
||||
ThirdPartyUser,
|
||||
isUser,
|
||||
} from "@budibase/types"
|
||||
import { sendEmail } from "../../utilities/email"
|
||||
import { EmailTemplatePurpose } from "../../constants"
|
||||
|
@ -265,8 +266,9 @@ export const save = async (
|
|||
await eventHelpers.handleSaveEvents(builtUser, dbUser)
|
||||
await addTenant(tenantId, _id, email)
|
||||
await cache.user.invalidateUser(response.id)
|
||||
|
||||
// let server know to sync user
|
||||
await apps.syncUserInApps(_id)
|
||||
await apps.syncUserInApps(_id, dbUser)
|
||||
|
||||
await Promise.all(groupPromises)
|
||||
|
||||
|
@ -572,7 +574,7 @@ export const destroy = async (id: string, currentUser: any) => {
|
|||
await cache.user.invalidateUser(userId)
|
||||
await sessions.invalidateSessions(userId, { reason: "deletion" })
|
||||
// let server know to sync user
|
||||
await apps.syncUserInApps(userId)
|
||||
await apps.syncUserInApps(userId, dbUser)
|
||||
}
|
||||
|
||||
const bulkDeleteProcessing = async (dbUser: User) => {
|
||||
|
@ -582,7 +584,7 @@ const bulkDeleteProcessing = async (dbUser: User) => {
|
|||
await cache.user.invalidateUser(userId)
|
||||
await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
|
||||
// let server know to sync user
|
||||
await apps.syncUserInApps(userId)
|
||||
await apps.syncUserInApps(userId, dbUser)
|
||||
}
|
||||
|
||||
export const invite = async (
|
||||
|
|
|
@ -2,6 +2,7 @@ import fetch from "node-fetch"
|
|||
import { constants, tenancy, logging } from "@budibase/backend-core"
|
||||
import { checkSlashesInUrl } from "../utilities"
|
||||
import env from "../environment"
|
||||
import { SyncUserRequest, User } from "@budibase/types"
|
||||
|
||||
async function makeAppRequest(url: string, method: string, body: any) {
|
||||
if (env.isTest()) {
|
||||
|
@ -24,11 +25,15 @@ 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 body: SyncUserRequest = {
|
||||
previousUser,
|
||||
}
|
||||
|
||||
const response = await makeAppRequest(
|
||||
`/api/users/metadata/sync/${userId}`,
|
||||
"POST",
|
||||
{}
|
||||
body
|
||||
)
|
||||
if (response && response.status !== 200) {
|
||||
throw "Unable to sync user."
|
||||
|
|
Loading…
Reference in New Issue