budibase/packages/builder/src/stores/portal/auth.js

162 lines
4.0 KiB
JavaScript

import { derived, writable, get } from "svelte/store"
import { API } from "api"
import { admin } from "stores/portal"
import analytics from "analytics"
export function createAuthStore() {
const auth = writable({
user: null,
accountPortalAccess: false,
tenantId: "default",
tenantSet: false,
loaded: false,
postLogout: false,
})
const store = derived(auth, $store => {
return {
user: $store.user,
accountPortalAccess: $store.accountPortalAccess,
tenantId: $store.tenantId,
tenantSet: $store.tenantSet,
loaded: $store.loaded,
postLogout: $store.postLogout,
isSSO: !!$store.user?.provider,
}
})
function setUser(user) {
auth.update(store => {
store.loaded = true
store.user = user
store.accountPortalAccess = user?.accountPortalAccess
if (user) {
store.tenantId = user.tenantId || "default"
store.tenantSet = true
}
return store
})
if (user) {
analytics
.activate()
.then(() => {
analytics.identify(user._id)
})
.catch(() => {
// This request may fail due to browser extensions blocking requests
// containing the word analytics, so we don't want to spam users with
// an error here.
})
}
}
async function setOrganisation(tenantId) {
const prevId = get(store).tenantId
auth.update(store => {
store.tenantId = tenantId
store.tenantSet = !!tenantId
return store
})
if (prevId !== tenantId) {
// re-init admin after setting org
await admin.init()
}
}
async function setInitInfo(info) {
await API.setInitInfo(info)
auth.update(store => {
store.initInfo = info
return store
})
return info
}
function setPostLogout() {
auth.update(store => {
store.postLogout = true
return store
})
}
async function getInitInfo() {
const info = await API.getInitInfo()
auth.update(store => {
store.initInfo = info
return store
})
return info
}
const actions = {
checkQueryString: async () => {
const urlParams = new URLSearchParams(window.location.search)
if (urlParams.has("tenantId")) {
const tenantId = urlParams.get("tenantId")
await setOrganisation(tenantId)
}
},
setOrg: async tenantId => {
await setOrganisation(tenantId)
},
getSelf: async () => {
// We need to catch this locally as we never want this to fail, even
// though normally we never want to swallow API errors at the store level.
// We're either logged in or we aren't.
// We also need to always update the loaded flag.
try {
const user = await API.fetchBuilderSelf()
setUser(user)
} catch (error) {
setUser(null)
}
},
login: async creds => {
const tenantId = get(store).tenantId
await API.logIn(tenantId, creds.username, creds.password)
await actions.getSelf()
},
logout: async () => {
await API.logOut()
setPostLogout()
setUser(null)
await setInitInfo({})
},
updateSelf: async fields => {
await API.updateSelf({ ...fields })
// Refetch to enrich after update.
try {
const user = await API.fetchBuilderSelf()
setUser(user)
} catch (error) {
setUser(null)
}
},
forgotPassword: async email => {
const tenantId = get(store).tenantId
await API.requestForgotPassword(tenantId, email)
},
resetPassword: async (password, resetCode) => {
const tenantId = get(store).tenantId
await API.resetPassword(tenantId, password, resetCode)
},
generateAPIKey: async () => {
return API.generateAPIKey()
},
fetchAPIKey: async () => {
const info = await API.fetchDeveloperInfo()
return info?.apiKey
},
}
return {
subscribe: store.subscribe,
setOrganisation,
getInitInfo,
setInitInfo,
...actions,
}
}
export const auth = createAuthStore()