Unify endpoints
This commit is contained in:
parent
c853d2c78e
commit
ff10fa422b
|
@ -4,19 +4,21 @@ import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global"
|
||||||
import { getFullUser } from "../../utilities/users"
|
import { getFullUser } from "../../utilities/users"
|
||||||
import {
|
import {
|
||||||
context,
|
context,
|
||||||
constants,
|
|
||||||
roles as rolesCore,
|
roles as rolesCore,
|
||||||
db as dbCore,
|
db as dbCore,
|
||||||
} from "@budibase/backend-core"
|
} from "@budibase/backend-core"
|
||||||
import { BBContext, Ctx, User } from "@budibase/types"
|
import { BBContext, Ctx, isUser, User } from "@budibase/types"
|
||||||
import sdk from "../../sdk"
|
import sdk from "../../sdk"
|
||||||
|
|
||||||
export async function syncUser(ctx: BBContext) {
|
export async function syncUser(ctx: Ctx) {
|
||||||
let deleting = false,
|
let deleting = false,
|
||||||
user: User | any
|
user: User | any
|
||||||
const userId = ctx.params.id
|
const userId = ctx.params.id
|
||||||
|
|
||||||
|
const previousUser = ctx.request.body?.previousUser
|
||||||
|
|
||||||
try {
|
try {
|
||||||
user = await getRawGlobalUser(userId)
|
user = (await getRawGlobalUser(userId)) as User
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err && err.status === 404) {
|
if (err && err.status === 404) {
|
||||||
user = {}
|
user = {}
|
||||||
|
@ -25,6 +27,11 @@ export async function syncUser(ctx: BBContext) {
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let previousApps = isUser(previousUser)
|
||||||
|
? Object.keys(previousUser.roles).map(appId => appId)
|
||||||
|
: []
|
||||||
|
|
||||||
const roles = deleting ? {} : user.roles
|
const roles = deleting ? {} : user.roles
|
||||||
// remove props which aren't useful to metadata
|
// remove props which aren't useful to metadata
|
||||||
delete user.password
|
delete user.password
|
||||||
|
@ -40,8 +47,9 @@ export async function syncUser(ctx: BBContext) {
|
||||||
.filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC)
|
.filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC)
|
||||||
.map(([appId]) => appId)
|
.map(([appId]) => appId)
|
||||||
}
|
}
|
||||||
for (let prodAppId of prodAppIds) {
|
for (let prodAppId of new Set([...prodAppIds, ...previousApps])) {
|
||||||
const roleId = roles[prodAppId]
|
const roleId = roles[prodAppId]
|
||||||
|
const deleteFromApp = !roleId
|
||||||
const devAppId = dbCore.getDevelopmentAppID(prodAppId)
|
const devAppId = dbCore.getDevelopmentAppID(prodAppId)
|
||||||
for (let appId of [prodAppId, devAppId]) {
|
for (let appId of [prodAppId, devAppId]) {
|
||||||
if (!(await dbCore.dbExists(appId))) {
|
if (!(await dbCore.dbExists(appId))) {
|
||||||
|
@ -54,24 +62,24 @@ export async function syncUser(ctx: BBContext) {
|
||||||
try {
|
try {
|
||||||
metadata = await db.get(metadataId)
|
metadata = await db.get(metadataId)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (deleting) {
|
if (deleteFromApp) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
metadata = {
|
metadata = {
|
||||||
tableId: InternalTables.USER_METADATA,
|
tableId: InternalTables.USER_METADATA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deleteFromApp) {
|
||||||
|
await db.remove(metadata)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// assign the roleId for the metadata doc
|
// assign the roleId for the metadata doc
|
||||||
if (roleId) {
|
if (roleId) {
|
||||||
metadata.roleId = roleId
|
metadata.roleId = roleId
|
||||||
}
|
}
|
||||||
let combined = !deleting
|
let combined = sdk.users.combineMetadataAndUser(user, metadata)
|
||||||
? sdk.users.combineMetadataAndUser(user, metadata)
|
|
||||||
: {
|
|
||||||
...metadata,
|
|
||||||
status: constants.UserStatus.INACTIVE,
|
|
||||||
metadata: rolesCore.BUILTIN_ROLE_IDS.PUBLIC,
|
|
||||||
}
|
|
||||||
// if its null then there was no updates required
|
// if its null then there was no updates required
|
||||||
if (combined) {
|
if (combined) {
|
||||||
await db.put(combined)
|
await db.put(combined)
|
||||||
|
@ -173,30 +181,3 @@ export async function getFlags(ctx: BBContext) {
|
||||||
}
|
}
|
||||||
ctx.body = doc
|
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}.`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -47,10 +47,5 @@ router
|
||||||
authorized(PermissionType.USER, PermissionLevel.READ),
|
authorized(PermissionType.USER, PermissionLevel.READ),
|
||||||
controller.getFlags
|
controller.getFlags
|
||||||
)
|
)
|
||||||
.delete(
|
|
||||||
"/api/users/metadata/:id/app/:prodAppId",
|
|
||||||
authorized(PermissionType.USER, PermissionLevel.WRITE),
|
|
||||||
controller.removeUserFromApp
|
|
||||||
)
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -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
|
return !!(user as User).roles
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
try {
|
||||||
// save the user to db
|
// save the user to db
|
||||||
let response = await db.put(builtUser)
|
let response = await db.put(builtUser)
|
||||||
|
@ -278,12 +267,8 @@ export const save = async (
|
||||||
await addTenant(tenantId, _id, email)
|
await addTenant(tenantId, _id, email)
|
||||||
await cache.user.invalidateUser(response.id)
|
await cache.user.invalidateUser(response.id)
|
||||||
|
|
||||||
for (const appId of appsToRemove) {
|
|
||||||
await apps.removeUserFromApp(_id, appId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// let server know to sync user
|
// let server know to sync user
|
||||||
await apps.syncUserInApps(_id)
|
await apps.syncUserInApps(_id, dbUser)
|
||||||
|
|
||||||
await Promise.all(groupPromises)
|
await Promise.all(groupPromises)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import fetch from "node-fetch"
|
||||||
import { constants, tenancy } from "@budibase/backend-core"
|
import { constants, tenancy } from "@budibase/backend-core"
|
||||||
import { checkSlashesInUrl } from "../utilities"
|
import { checkSlashesInUrl } from "../utilities"
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
|
import { User } from "@budibase/types"
|
||||||
|
|
||||||
async function makeAppRequest(url: string, method: string, body: any) {
|
async function makeAppRequest(url: string, method: string, body: any) {
|
||||||
if (env.isTest()) {
|
if (env.isTest()) {
|
||||||
|
@ -20,24 +21,13 @@ async function makeAppRequest(url: string, method: string, body: any) {
|
||||||
return fetch(checkSlashesInUrl(env.APPS_URL + url), request)
|
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(
|
const response = await makeAppRequest(
|
||||||
`/api/users/metadata/sync/${userId}`,
|
`/api/users/metadata/sync/${userId}`,
|
||||||
"POST",
|
"POST",
|
||||||
{}
|
{ previousUser }
|
||||||
)
|
)
|
||||||
if (response && response.status !== 200) {
|
if (response && response.status !== 200) {
|
||||||
throw "Unable to sync user."
|
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."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue