Identity updates
This commit is contained in:
parent
ff48aaec6e
commit
b3f04e7e8f
|
@ -76,17 +76,10 @@ exports.isMultiTenant = () => {
|
||||||
exports.doInTenant = (tenantId, task) => {
|
exports.doInTenant = (tenantId, task) => {
|
||||||
// the internal function is so that we can re-use an existing
|
// the internal function is so that we can re-use an existing
|
||||||
// context - don't want to close DB on a parent context
|
// context - don't want to close DB on a parent context
|
||||||
async function internal(opts = { existing: false, user: undefined }) {
|
async function internal(opts = { existing: false }) {
|
||||||
// preserve the user
|
|
||||||
if (user) {
|
|
||||||
exports.setUser(user)
|
|
||||||
}
|
|
||||||
// set the tenant id
|
// set the tenant id
|
||||||
if (!opts.existing) {
|
if (!opts.existing) {
|
||||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
exports.updateTenantId(tenantId)
|
||||||
if (env.USE_COUCH) {
|
|
||||||
exports.setGlobalDB(tenantId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -102,15 +95,14 @@ exports.doInTenant = (tenantId, task) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = cls.getFromContext(ContextKeys.USER)
|
|
||||||
const using = cls.getFromContext(ContextKeys.IN_USE)
|
const using = cls.getFromContext(ContextKeys.IN_USE)
|
||||||
if (using && cls.getFromContext(ContextKeys.TENANT_ID) === tenantId) {
|
if (using && cls.getFromContext(ContextKeys.TENANT_ID) === tenantId) {
|
||||||
cls.setOnContext(ContextKeys.IN_USE, using + 1)
|
cls.setOnContext(ContextKeys.IN_USE, using + 1)
|
||||||
return internal({ existing: true, user })
|
return internal({ existing: true })
|
||||||
} else {
|
} else {
|
||||||
return cls.run(async () => {
|
return cls.run(async () => {
|
||||||
cls.setOnContext(ContextKeys.IN_USE, 1)
|
cls.setOnContext(ContextKeys.IN_USE, 1)
|
||||||
return internal({ existing: false, user })
|
return internal()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,19 +138,19 @@ exports.doInAppContext = (appId, task) => {
|
||||||
throw new Error("appId is required")
|
throw new Error("appId is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = exports.getUser()
|
||||||
|
|
||||||
// the internal function is so that we can re-use an existing
|
// the internal function is so that we can re-use an existing
|
||||||
// context - don't want to close DB on a parent context
|
// context - don't want to close DB on a parent context
|
||||||
async function internal(opts = { existing: false, user: undefined }) {
|
async function internal(opts = { existing: false, user: undefined }) {
|
||||||
// preserve the user
|
|
||||||
if (user) {
|
|
||||||
exports.setUser(user)
|
|
||||||
}
|
|
||||||
// set the app tenant id
|
// set the app tenant id
|
||||||
if (!opts.existing) {
|
if (!opts.existing) {
|
||||||
setAppTenantId(appId)
|
setAppTenantId(appId)
|
||||||
}
|
}
|
||||||
// set the app ID
|
// set the app ID
|
||||||
cls.setOnContext(ContextKeys.APP_ID, appId)
|
cls.setOnContext(ContextKeys.APP_ID, appId)
|
||||||
|
// preserve the user
|
||||||
|
exports.setUser(user)
|
||||||
try {
|
try {
|
||||||
// invoke the task
|
// invoke the task
|
||||||
return await task()
|
return await task()
|
||||||
|
@ -171,29 +163,56 @@ exports.doInAppContext = (appId, task) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const user = cls.getFromContext(ContextKeys.USER)
|
|
||||||
const using = cls.getFromContext(ContextKeys.IN_USE)
|
const using = cls.getFromContext(ContextKeys.IN_USE)
|
||||||
if (using && cls.getFromContext(ContextKeys.APP_ID) === appId) {
|
if (using && cls.getFromContext(ContextKeys.APP_ID) === appId) {
|
||||||
cls.setOnContext(ContextKeys.IN_USE, using + 1)
|
cls.setOnContext(ContextKeys.IN_USE, using + 1)
|
||||||
return internal({ existing: true, user })
|
return internal({ existing: true })
|
||||||
} else {
|
} else {
|
||||||
return cls.run(async () => {
|
return cls.run(async () => {
|
||||||
cls.setOnContext(ContextKeys.IN_USE, 1)
|
cls.setOnContext(ContextKeys.IN_USE, 1)
|
||||||
return internal({ existing: false, user })
|
return internal()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.doInUserContext = (user, task) => {
|
exports.doInUserContext = (user, task) => {
|
||||||
return cls.run(() => {
|
if (!user) {
|
||||||
let tenantId = user.tenantId
|
throw new Error("user is required")
|
||||||
if (!tenantId) {
|
|
||||||
tenantId = exports.getTenantId()
|
|
||||||
}
|
}
|
||||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
|
||||||
exports.setUser(user)
|
async function internal(opts = { existing: false }) {
|
||||||
return task()
|
if (!opts.existing) {
|
||||||
|
cls.setOnContext(ContextKeys.USER, user)
|
||||||
|
// set the tenant so that doInTenant will preserve user
|
||||||
|
if (user.tenantId) {
|
||||||
|
exports.updateTenantId(user.tenantId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// invoke the task
|
||||||
|
return await task()
|
||||||
|
} finally {
|
||||||
|
const using = cls.getFromContext(ContextKeys.IN_USE)
|
||||||
|
if (!using || using <= 1) {
|
||||||
|
exports.setUser(null)
|
||||||
|
} else {
|
||||||
|
cls.setOnContext(using - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = cls.getFromContext(ContextKeys.USER)
|
||||||
|
const using = cls.getFromContext(ContextKeys.IN_USE)
|
||||||
|
if (using && existing && existing._id === user._id) {
|
||||||
|
cls.setOnContext(ContextKeys.IN_USE, using + 1)
|
||||||
|
return internal({ existing: true })
|
||||||
|
} else {
|
||||||
|
return cls.run(async () => {
|
||||||
|
cls.setOnContext(ContextKeys.IN_USE, 1)
|
||||||
|
return internal({ existing: false })
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.setUser = user => {
|
exports.setUser = user => {
|
||||||
|
@ -202,8 +221,7 @@ exports.setUser = user => {
|
||||||
|
|
||||||
exports.getUser = () => {
|
exports.getUser = () => {
|
||||||
try {
|
try {
|
||||||
const user = cls.getFromContext(ContextKeys.USER)
|
return cls.getFromContext(ContextKeys.USER)
|
||||||
return user
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// do nothing - user is not in context
|
// do nothing - user is not in context
|
||||||
}
|
}
|
||||||
|
@ -211,7 +229,9 @@ exports.getUser = () => {
|
||||||
|
|
||||||
exports.updateTenantId = tenantId => {
|
exports.updateTenantId = tenantId => {
|
||||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
||||||
|
if (env.USE_COUCH) {
|
||||||
exports.setGlobalDB(tenantId)
|
exports.setGlobalDB(tenantId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.updateAppId = async appId => {
|
exports.updateAppId = async appId => {
|
||||||
|
|
|
@ -4,6 +4,6 @@ import * as identification from "./identification"
|
||||||
|
|
||||||
export const publishEvent = async (event: Event, properties: any) => {
|
export const publishEvent = async (event: Event, properties: any) => {
|
||||||
// in future this should use async events via a distributed queue.
|
// in future this should use async events via a distributed queue.
|
||||||
const identity = identification.getCurrentIdentity()
|
const identity = await identification.getCurrentIdentity()
|
||||||
await processors.processEvent(event, identity, properties)
|
await processors.processEvent(event, identity, properties)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,25 @@ import {
|
||||||
BudibaseIdentity,
|
BudibaseIdentity,
|
||||||
isCloudAccount,
|
isCloudAccount,
|
||||||
isSSOAccount,
|
isSSOAccount,
|
||||||
|
TenantIdentity,
|
||||||
|
SettingsConfig,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { analyticsProcessor } from "./processors"
|
import { analyticsProcessor } from "./processors"
|
||||||
|
import * as dbUtils from "../db/utils"
|
||||||
|
import { Configs } from "../constants"
|
||||||
|
import * as hashing from "../hashing"
|
||||||
|
|
||||||
export const getCurrentIdentity = (): Identity => {
|
export const getCurrentIdentity = async (): Promise<Identity> => {
|
||||||
const user: SessionUser | undefined = context.getUser()
|
const user: SessionUser | undefined = context.getUser()
|
||||||
const tenantId = context.getTenantId()
|
let tenantId = context.getTenantId()
|
||||||
let id: string
|
let id: string
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
id = user._id
|
id = user._id
|
||||||
} else if (env.SELF_HOSTED) {
|
|
||||||
id = "installationId" // TODO
|
|
||||||
} else {
|
} else {
|
||||||
id = tenantId
|
const global = await getGlobalIdentifiers(tenantId)
|
||||||
|
id = global.id
|
||||||
|
tenantId = global.tenantId
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -33,6 +38,55 @@ export const getCurrentIdentity = (): Identity => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getGlobalId = async (): Promise<string> => {
|
||||||
|
const db = context.getGlobalDB()
|
||||||
|
const config: SettingsConfig = await dbUtils.getScopedFullConfig(db, {
|
||||||
|
type: Configs.SETTINGS,
|
||||||
|
})
|
||||||
|
if (config.config.globalId) {
|
||||||
|
return config.config.globalId
|
||||||
|
} else {
|
||||||
|
const globalId = `global_${hashing.newid()}`
|
||||||
|
config.config.globalId = globalId
|
||||||
|
await db.put(config)
|
||||||
|
return globalId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGlobalIdentifiers = async (
|
||||||
|
tenantId: string
|
||||||
|
): Promise<{ id: string; tenantId: string }> => {
|
||||||
|
if (env.SELF_HOSTED) {
|
||||||
|
const globalId = await getGlobalId()
|
||||||
|
return {
|
||||||
|
id: globalId,
|
||||||
|
tenantId: `${globalId}-${tenantId}`,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// tenant id's in the cloud are already unique
|
||||||
|
return {
|
||||||
|
id: tenantId,
|
||||||
|
tenantId: tenantId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getHostingFromEnv = () => {
|
||||||
|
return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
|
||||||
|
}
|
||||||
|
|
||||||
|
export const identifyTenant = async (tenantId: string) => {
|
||||||
|
const global = await getGlobalIdentifiers(tenantId)
|
||||||
|
|
||||||
|
const identity: TenantIdentity = {
|
||||||
|
id: global.id,
|
||||||
|
tenantId: global.tenantId,
|
||||||
|
hosting: getHostingFromEnv(),
|
||||||
|
type: IdentityType.TENANT,
|
||||||
|
}
|
||||||
|
await identify(identity)
|
||||||
|
}
|
||||||
|
|
||||||
export const identifyUser = async (user: User) => {
|
export const identifyUser = async (user: User) => {
|
||||||
const id = user._id as string
|
const id = user._id as string
|
||||||
const tenantId = user.tenantId
|
const tenantId = user.tenantId
|
||||||
|
@ -40,7 +94,7 @@ export const identifyUser = async (user: User) => {
|
||||||
const type = IdentityType.USER
|
const type = IdentityType.USER
|
||||||
let builder = user.builder?.global
|
let builder = user.builder?.global
|
||||||
let admin = user.admin?.global
|
let admin = user.admin?.global
|
||||||
let authType = user.providerType ? user.providerType : "password"
|
let providerType = user.providerType
|
||||||
|
|
||||||
const identity: BudibaseIdentity = {
|
const identity: BudibaseIdentity = {
|
||||||
id,
|
id,
|
||||||
|
@ -49,7 +103,7 @@ export const identifyUser = async (user: User) => {
|
||||||
type,
|
type,
|
||||||
builder,
|
builder,
|
||||||
admin,
|
admin,
|
||||||
authType,
|
providerType,
|
||||||
}
|
}
|
||||||
|
|
||||||
await identify(identity)
|
await identify(identity)
|
||||||
|
@ -60,9 +114,7 @@ export const identifyAccount = async (account: Account) => {
|
||||||
const tenantId = account.tenantId
|
const tenantId = account.tenantId
|
||||||
const hosting = account.hosting
|
const hosting = account.hosting
|
||||||
let type = IdentityType.ACCOUNT
|
let type = IdentityType.ACCOUNT
|
||||||
let authType = isSSOAccount(account)
|
let providerType = isSSOAccount(account) ? account.providerType : undefined
|
||||||
? (account.providerType as string)
|
|
||||||
: "password"
|
|
||||||
|
|
||||||
if (isCloudAccount(account)) {
|
if (isCloudAccount(account)) {
|
||||||
if (account.budibaseUserId) {
|
if (account.budibaseUserId) {
|
||||||
|
@ -77,7 +129,7 @@ export const identifyAccount = async (account: Account) => {
|
||||||
tenantId,
|
tenantId,
|
||||||
hosting,
|
hosting,
|
||||||
type,
|
type,
|
||||||
authType,
|
providerType,
|
||||||
verified: account.verified,
|
verified: account.verified,
|
||||||
profession: account.profession,
|
profession: account.profession,
|
||||||
companySize: account.size,
|
companySize: account.size,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { processors } from "./processors"
|
import { processors } from "./processors"
|
||||||
export * from "./publishers"
|
export * from "./publishers"
|
||||||
export * as analytics from "./analytics"
|
export * as analytics from "./analytics"
|
||||||
|
export * as identification from "./identification"
|
||||||
|
|
||||||
export const shutdown = () => {
|
export const shutdown = () => {
|
||||||
processors.shutdown()
|
processors.shutdown()
|
||||||
|
|
|
@ -79,14 +79,14 @@ exports.authenticateThirdParty = async function (
|
||||||
dbUser.forceResetPassword = false
|
dbUser.forceResetPassword = false
|
||||||
|
|
||||||
// create or sync the user
|
// create or sync the user
|
||||||
let response
|
|
||||||
try {
|
try {
|
||||||
response = await saveUserFn(dbUser, false, false)
|
await saveUserFn(dbUser, false, false)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return authError(done, err)
|
return authError(done, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbUser._rev = response.rev
|
// now that we're sure user exists, load them from the db
|
||||||
|
dbUser = await users.getGlobalUserByEmail(thirdPartyUser.email)
|
||||||
|
|
||||||
// authenticate
|
// authenticate
|
||||||
const sessionId = newid()
|
const sessionId = newid()
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
"dist/**/*",
|
||||||
"**/*.spec.js",
|
"**/*.spec.js",
|
||||||
"**/*.spec.ts"
|
"**/*.spec.ts"
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
"dist/**/*",
|
||||||
"**/*.spec.js",
|
"**/*.spec.js",
|
||||||
// "**/*.spec.ts" // don't exclude spec.ts files for editor support
|
// "**/*.spec.ts" // don't exclude spec.ts files for editor support
|
||||||
]
|
]
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface SettingsConfig extends Config {
|
||||||
company: string
|
company: string
|
||||||
logoUrl: string
|
logoUrl: string
|
||||||
platformUrl: string
|
platformUrl: string
|
||||||
|
globalId?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ export interface User extends Document {
|
||||||
}
|
}
|
||||||
providerType?: string
|
providerType?: string
|
||||||
tenantId: string
|
tenantId: string
|
||||||
|
email: string
|
||||||
|
password?: string
|
||||||
|
status?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserRoles {
|
export interface UserRoles {
|
||||||
|
|
|
@ -11,10 +11,15 @@ export interface Identity {
|
||||||
tenantId: string
|
tenantId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserIdentity extends Identity {
|
export interface TenantIdentity extends Identity {
|
||||||
hosting: Hosting
|
hosting: Hosting
|
||||||
type: IdentityType
|
type: IdentityType
|
||||||
authType: string
|
}
|
||||||
|
|
||||||
|
export interface UserIdentity extends TenantIdentity {
|
||||||
|
hosting: Hosting
|
||||||
|
type: IdentityType
|
||||||
|
providerType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BudibaseIdentity extends UserIdentity {
|
export interface BudibaseIdentity extends UserIdentity {
|
||||||
|
|
|
@ -2,13 +2,15 @@ import { EmailTemplatePurpose } from "../../../constants"
|
||||||
import { checkInviteCode } from "../../../utilities/redis"
|
import { checkInviteCode } from "../../../utilities/redis"
|
||||||
import { sendEmail } from "../../../utilities/email"
|
import { sendEmail } from "../../../utilities/email"
|
||||||
import { users } from "../../../sdk"
|
import { users } from "../../../sdk"
|
||||||
|
import { User } from "@budibase/types"
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
import { getGlobalDB } from "@budibase/backend-core/dist/src/context"
|
||||||
|
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
users: usersCore,
|
users: usersCore,
|
||||||
tenancy,
|
tenancy,
|
||||||
db: dbUtils,
|
db: dbUtils,
|
||||||
events,
|
|
||||||
} = require("@budibase/backend-core")
|
} = require("@budibase/backend-core")
|
||||||
|
|
||||||
export const save = async (ctx: any) => {
|
export const save = async (ctx: any) => {
|
||||||
|
@ -48,10 +50,9 @@ export const adminUser = async (ctx: any) => {
|
||||||
ctx.throw(403, "You cannot initialise once a global user has been created.")
|
ctx.throw(403, "You cannot initialise once a global user has been created.")
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = {
|
const user: User = {
|
||||||
email: email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
createdAt: Date.now(),
|
|
||||||
roles: {},
|
roles: {},
|
||||||
builder: {
|
builder: {
|
||||||
global: true,
|
global: true,
|
||||||
|
@ -65,6 +66,7 @@ export const adminUser = async (ctx: any) => {
|
||||||
ctx.body = await tenancy.doInTenant(tenantId, async () => {
|
ctx.body = await tenancy.doInTenant(tenantId, async () => {
|
||||||
return users.save(user, hashPassword, requirePassword)
|
return users.save(user, hashPassword, requirePassword)
|
||||||
})
|
})
|
||||||
|
await events.identification.identifyTenant(tenantId)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ctx.throw(err.status || 400, err)
|
ctx.throw(err.status || 400, err)
|
||||||
}
|
}
|
||||||
|
@ -132,15 +134,17 @@ export const inviteAccept = async (ctx: any) => {
|
||||||
// info is an extension of the user object that was stored by global
|
// info is an extension of the user object that was stored by global
|
||||||
const { email, info }: any = await checkInviteCode(inviteCode)
|
const { email, info }: any = await checkInviteCode(inviteCode)
|
||||||
ctx.body = await tenancy.doInTenant(info.tenantId, async () => {
|
ctx.body = await tenancy.doInTenant(info.tenantId, async () => {
|
||||||
const user = await users.save({
|
const saved = await users.save({
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
...info,
|
...info,
|
||||||
})
|
})
|
||||||
|
const db = getGlobalDB()
|
||||||
|
const user = await db.get(saved._id)
|
||||||
await events.user.inviteAccepted(user)
|
await events.user.inviteAccepted(user)
|
||||||
return user
|
return saved
|
||||||
})
|
})
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
|
if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import env from "../../environment"
|
||||||
import { quotas } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
import * as apps from "../../utilities/appService"
|
import * as apps from "../../utilities/appService"
|
||||||
import * as eventHelpers from "./events"
|
import * as eventHelpers from "./events"
|
||||||
|
import { User } from "@budibase/types"
|
||||||
|
|
||||||
const {
|
const {
|
||||||
tenancy,
|
tenancy,
|
||||||
|
@ -16,6 +17,8 @@ const {
|
||||||
HTTPError,
|
HTTPError,
|
||||||
} = require("@budibase/backend-core")
|
} = require("@budibase/backend-core")
|
||||||
|
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all users from the current tenancy.
|
* Retrieves all users from the current tenancy.
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +54,7 @@ export const getUser = async (userId: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const save = async (
|
export const save = async (
|
||||||
user: any,
|
user: User,
|
||||||
hashPassword = true,
|
hashPassword = true,
|
||||||
requirePassword = true
|
requirePassword = true
|
||||||
) => {
|
) => {
|
||||||
|
@ -97,7 +100,7 @@ export const save = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_id) {
|
if (!_id) {
|
||||||
_id = dbUtils.generateGlobalUserID(email)
|
_id = dbUtils.generateGlobalUserID()
|
||||||
}
|
}
|
||||||
|
|
||||||
user = {
|
user = {
|
||||||
|
@ -130,7 +133,7 @@ export const save = async (
|
||||||
user._rev = response.rev
|
user._rev = response.rev
|
||||||
|
|
||||||
await eventHelpers.handleSaveEvents(user, dbUser)
|
await eventHelpers.handleSaveEvents(user, dbUser)
|
||||||
|
await events.identification.identifyUser(user)
|
||||||
await tenancy.tryAddTenant(tenantId, _id, email)
|
await tenancy.tryAddTenant(tenantId, _id, email)
|
||||||
await cache.user.invalidateUser(response.id)
|
await cache.user.invalidateUser(response.id)
|
||||||
// let server know to sync user
|
// let server know to sync user
|
||||||
|
|
Loading…
Reference in New Issue