diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 54280d2ef3..da038d4818 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -46,7 +46,7 @@ }, "devDependencies": { "@shopify/jest-koa-mocks": "^3.1.5", - "@budibase/types": "^1.0.126-alpha.0", + "@budibase/types": "^1.0.167-alpha.8", "@types/jest": "^27.4.1", "@types/koa": "^2.13.3", "@types/node": "^15.12.4", diff --git a/packages/backend-core/src/context/index.js b/packages/backend-core/src/context/index.js index 20e5e26693..2af8b9b0f8 100644 --- a/packages/backend-core/src/context/index.js +++ b/packages/backend-core/src/context/index.js @@ -16,6 +16,7 @@ const ContextKeys = { TENANT_ID: "tenantId", GLOBAL_DB: "globalDb", APP_ID: "appId", + USER: "user", // whatever the request app DB was CURRENT_DB: "currentDb", // get the prod app DB from the request @@ -173,6 +174,21 @@ exports.doInAppContext = (appId, task) => { } } +exports.doInUserContext = (user, task) => { + return cls.run(async () => { + cls.setOnContext(ContextKeys.USER, user) + return task() + }) +} + +exports.getUser = () => { + try { + return cls.getFromContext(ContextKeys.USER) + } catch (e) { + // do nothing - user is not in context + } +} + exports.updateTenantId = tenantId => { cls.setOnContext(ContextKeys.TENANT_ID, tenantId) exports.setGlobalDB(tenantId) diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index a4e06d8217..9bf1abd18c 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -10,6 +10,7 @@ import { getAppMetadata } from "../cache/appMetadata" import { checkSlashesInUrl } from "../helpers" import { isDevApp, isDevAppID } from "./conversions" import { APP_PREFIX } from "./constants" +import * as events from "../events" const UNICODE_MAX = "\ufff0" @@ -380,15 +381,19 @@ export const getScopedFullConfig = async function ( )[0] // custom logic for settings doc - // always provide the platform URL if (type === Configs.SETTINGS) { if (scopedConfig && scopedConfig.doc) { + // overrides affected by environment variables scopedConfig.doc.config.platformUrl = await getPlatformUrl() + scopedConfig.doc.config.analyticsEnabled = + await events.analytics.enabled() } else { + // defaults scopedConfig = { doc: { config: { platformUrl: await getPlatformUrl(), + analyticsEnabled: await events.analytics.enabled(), }, }, } diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 9210355283..417fcd7866 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -16,7 +16,7 @@ if (!LOADED && isDev() && !isTest()) { LOADED = true } -export = { +const env: any = { isTest, isDev, JWT_SECRET: process.env.JWT_SECRET, @@ -59,9 +59,11 @@ export = { } // clean up any environment variable edge cases -for (let [key, value] of Object.entries(module.exports)) { +for (let [key, value] of Object.entries(env)) { // handle the edge case of "0" to disable an environment variable if (value === "0") { - module.exports[key] = 0 + env[key] = 0 } } + +export = env diff --git a/packages/backend-core/src/events/analytics.ts b/packages/backend-core/src/events/analytics.ts new file mode 100644 index 0000000000..e2f219f554 --- /dev/null +++ b/packages/backend-core/src/events/analytics.ts @@ -0,0 +1,45 @@ +import env from "../environment" +import * as tenancy from "../tenancy" +import * as dbUtils from "../db/utils" +import { Configs } from "../constants" + +export const enabled = async () => { + // cloud - always use the environment variable + if (!env.SELF_HOSTED) { + return !!env.ENABLE_ANALYTICS + } + + // self host - prefer the settings doc + // check for explicit true/false values to support + // backwards compatibility where setting may not exist + const settings = await getSettingsDoc() + if (settings?.config?.analyticsEnabled === false) { + return false + } else if (settings?.config?.analyticsEnabled === true) { + return true + } + + // fallback to the environment variable + // explicitly check for 0 or false here, undefined or otherwise is treated as true + const envEnabled: any = env.ENABLE_ANALYTICS + if (envEnabled === 0 || envEnabled === false) { + return false + } else { + return true + } +} + +const getSettingsDoc = async () => { + const db = tenancy.getGlobalDB() + let settings + try { + settings = await db.get( + dbUtils.generateConfigID({ type: Configs.SETTINGS }) + ) + } catch (e: any) { + if (e.status !== 404) { + throw e + } + } + return settings +} diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 8234a13b13..21dfba6090 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,9 +1,9 @@ import { Event } from "@budibase/types" import { processors } from "./processors" +import * as identification from "./identification" -export const publishEvent = (event: Event, properties: any) => { - // in future this should use async events - // via a queue. For now we can use sync as - // this is non-blocking - processors.processEvent(event, properties) +export const publishEvent = async (event: Event, properties: any) => { + // in future this should use async events via a distributed queue. + const identity = identification.getCurrentIdentity() + await processors.processEvent(event, identity, properties) } diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts new file mode 100644 index 0000000000..f86d6abe46 --- /dev/null +++ b/packages/backend-core/src/events/identification.ts @@ -0,0 +1,93 @@ +import { + isCloudAccount, + isSSOAccount, +} from "./../../../types/src/documents/account/account" +import * as context from "../context" +import env from "../environment" +import { + Hosting, + User, + SessionUser, + Identity, + IdentityType, + Account, + AccountIdentity, + BudibaseIdentity, +} from "@budibase/types" +import { analyticsProcessor } from "./processors" + +export const getCurrentIdentity = (): Identity => { + const user: SessionUser | undefined = context.getUser() + const tenantId = context.getTenantId() + let id: string + + if (user) { + id = user._id + } else if (env.SELF_HOSTED) { + id = "installationId" // TODO + } else { + id = context.getTenantId() + } + + return { + id, + tenantId, + } +} + +export const identifyUser = async (user: User) => { + const id = user._id as string + const tenantId = user.tenantId + const hosting = env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD + const type = IdentityType.USER + let builder = user.builder?.global + let admin = user.admin?.global + let authType = user.providerType ? user.providerType : "password" + + const identity: BudibaseIdentity = { + id, + tenantId, + hosting, + type, + builder, + admin, + authType, + } + + await identify(identity) +} + +export const identifyAccount = async (account: Account) => { + let id = account.accountId + const tenantId = account.tenantId + const hosting = account.hosting + let type = IdentityType.ACCOUNT + let authType = isSSOAccount(account) + ? (account.providerType as string) + : "password" + + if (isCloudAccount(account)) { + if (account.budibaseUserId) { + // use the budibase user as the id if set + id = account.budibaseUserId + type = IdentityType.USER + } + } + + const identity: AccountIdentity = { + id, + tenantId, + hosting, + type, + authType, + verified: account.verified, + profession: account.profession, + companySize: account.size, + } + + await identify(identity) +} + +const identify = async (identity: Identity) => { + await analyticsProcessor.identify(identity) +} diff --git a/packages/backend-core/src/events/index.ts b/packages/backend-core/src/events/index.ts index 08d82e5112..e850ea8b26 100644 --- a/packages/backend-core/src/events/index.ts +++ b/packages/backend-core/src/events/index.ts @@ -1,10 +1,7 @@ import { processors } from "./processors" export * from "./publishers" +export * as analytics from "./analytics" export const shutdown = () => { processors.shutdown() } - -export const analyticsEnabled = () => { - return true -} diff --git a/packages/backend-core/src/events/processors/AnalyticsProcessor.ts b/packages/backend-core/src/events/processors/AnalyticsProcessor.ts new file mode 100644 index 0000000000..d2f82d59fb --- /dev/null +++ b/packages/backend-core/src/events/processors/AnalyticsProcessor.ts @@ -0,0 +1,43 @@ +import { Event, Identity } from "@budibase/types" +import { EventProcessor } from "./types" +import env from "../../environment" +import * as analytics from "../analytics" +import PosthogProcessor from "./PosthogProcessor" + +export default class AnalyticsProcessor implements EventProcessor { + posthog: PosthogProcessor | undefined + + constructor() { + if (env.POSTHOG_TOKEN) { + this.posthog = new PosthogProcessor(env.POSTHOG_TOKEN) + } + } + + async processEvent( + event: Event, + identity: Identity, + properties: any + ): Promise { + if (!(await analytics.enabled())) { + return + } + if (this.posthog) { + this.posthog.processEvent(event, identity, properties) + } + } + + async identify(identity: Identity) { + if (!(await analytics.enabled())) { + return + } + if (this.posthog) { + this.posthog.identify(identity) + } + } + + shutdown() { + if (this.posthog) { + this.posthog.shutdown() + } + } +} diff --git a/packages/backend-core/src/events/processors/LoggingProcessor.ts b/packages/backend-core/src/events/processors/LoggingProcessor.ts index 8c46f0649a..1094411298 100644 --- a/packages/backend-core/src/events/processors/LoggingProcessor.ts +++ b/packages/backend-core/src/events/processors/LoggingProcessor.ts @@ -1,12 +1,15 @@ -import { Event } from "@budibase/types" -import { getTenantId } from "../../context" +import { Event, Identity } from "@budibase/types" import { EventProcessor } from "./types" export default class LoggingProcessor implements EventProcessor { - processEvent(event: Event, properties: any): void { - const tenantId = getTenantId() - const userId = getTenantId() // TODO - console.log(`[audit] [tenant=${tenantId}] [user=${userId}] ${event}`) + async processEvent( + event: Event, + identity: Identity, + properties: any + ): Promise { + console.log( + `[audit] [tenant=${identity.tenantId}] [identity=${identity.id}] ${event}` + ) } shutdown(): void { diff --git a/packages/backend-core/src/events/processors/PosthogProcessor.ts b/packages/backend-core/src/events/processors/PosthogProcessor.ts index e97ae6680c..499f69f581 100644 --- a/packages/backend-core/src/events/processors/PosthogProcessor.ts +++ b/packages/backend-core/src/events/processors/PosthogProcessor.ts @@ -1,7 +1,6 @@ import PostHog from "posthog-node" -import { Event } from "@budibase/types" +import { Event, Identity } from "@budibase/types" import { EventProcessor } from "./types" -import { getTenantId } from "../../context" export default class PosthogProcessor implements EventProcessor { posthog: PostHog @@ -13,13 +12,16 @@ export default class PosthogProcessor implements EventProcessor { this.posthog = new PostHog(token) } - processEvent(event: Event, properties: any): void { - const userId = getTenantId() // TODO - this.posthog.capture({ distinctId: userId, event, properties }) + async processEvent( + event: Event, + identity: Identity, + properties: any + ): Promise { + this.posthog.capture({ distinctId: identity.id, event, properties }) } - identify(distinctId: string, properties: any) { - this.posthog.identify({ distinctId, properties }) + async identify(identity: Identity) { + this.posthog.identify({ distinctId: identity.id, properties: identity }) } shutdown() { diff --git a/packages/backend-core/src/events/processors/Processors.ts b/packages/backend-core/src/events/processors/Processors.ts index 2b77fa90b2..ed23af4780 100644 --- a/packages/backend-core/src/events/processors/Processors.ts +++ b/packages/backend-core/src/events/processors/Processors.ts @@ -1,22 +1,21 @@ -import { Event } from "@budibase/types" +import { Event, Identity } from "@budibase/types" import { EventProcessor } from "./types" -import env from "../../environment" -import LoggingProcessor from "./LoggingProcessor" -import PosthogProcessor from "./PosthogProcessor" export default class Processor implements EventProcessor { + initialised: boolean = false processors: EventProcessor[] = [] - constructor() { - if (env.ENABLE_ANALYTICS && env.POSTHOG_TOKEN) { - this.processors.push(new PosthogProcessor(env.POSTHOG_TOKEN)) - } - this.processors.push(new LoggingProcessor()) + constructor(processors: EventProcessor[]) { + this.processors = processors } - processEvent(event: Event, properties: any): void { + async processEvent( + event: Event, + identity: Identity, + properties: any + ): Promise { for (const eventProcessor of this.processors) { - eventProcessor.processEvent(event, properties) + await eventProcessor.processEvent(event, identity, properties) } } @@ -25,39 +24,4 @@ export default class Processor implements EventProcessor { eventProcessor.shutdown() } } - - // Identity todo - - // export const identify(type: IdentityType, id: string, hosting?: Hosting) { - // const tenantId = getTenantId() - // if (!hosting) { - // hosting = env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD - // } - // const properties = { - // type, - // hosting, - // tenantId, - // } - // this.posthog!.identify(id, properties) - // } - - // identifyUser(userId: string) { - // this.identify(IdentityType.USER, userId) - // } - - // identifyTenant() { - // let distinctId - // if (env.SELF_HOSTED) { - // distinctId = getTenantId() // TODO: Get installation ID - // } else { - // distinctId = getTenantId() - // } - // this.identify(IdentityType.TENANT, distinctId) - // } - - // identifyAccount(account: Account) { - // const distinctId = account.accountId - // const hosting = account.hosting - // this.identify(IdentityType.ACCOUNT, distinctId, hosting) - // } } diff --git a/packages/backend-core/src/events/processors/index.ts b/packages/backend-core/src/events/processors/index.ts index 9269648ff2..0e75f050db 100644 --- a/packages/backend-core/src/events/processors/index.ts +++ b/packages/backend-core/src/events/processors/index.ts @@ -1,2 +1,8 @@ +import AnalyticsProcessor from "./AnalyticsProcessor" +import LoggingProcessor from "./LoggingProcessor" import Processors from "./Processors" -export const processors = new Processors() + +export const analyticsProcessor = new AnalyticsProcessor() +const loggingProcessor = new LoggingProcessor() + +export const processors = new Processors([analyticsProcessor, loggingProcessor]) diff --git a/packages/backend-core/src/events/processors/types.ts b/packages/backend-core/src/events/processors/types.ts index c5d32f6c75..0be1606351 100644 --- a/packages/backend-core/src/events/processors/types.ts +++ b/packages/backend-core/src/events/processors/types.ts @@ -1,4 +1,4 @@ -import { Event } from "@budibase/types" +import { Event, Identity } from "@budibase/types" export enum EventProcessorType { POSTHOG = "posthog", @@ -6,6 +6,6 @@ export enum EventProcessorType { } export interface EventProcessor { - processEvent(event: Event, properties: any): void + processEvent(event: Event, identity: Identity, properties: any): Promise shutdown(): void } diff --git a/packages/backend-core/src/events/publishers/account.ts b/packages/backend-core/src/events/publishers/account.ts index 34ca42db02..66780a0b56 100644 --- a/packages/backend-core/src/events/publishers/account.ts +++ b/packages/backend-core/src/events/publishers/account.ts @@ -1,17 +1,17 @@ import { publishEvent } from "../events" import { Event, Account } from "@budibase/types" -export function created(account: Account) { +export async function created(account: Account) { const properties = {} - publishEvent(Event.ACCOUNT_CREATED, properties) + await publishEvent(Event.ACCOUNT_CREATED, properties) } -export function deleted(account: Account) { +export async function deleted(account: Account) { const properties = {} - publishEvent(Event.ACCOUNT_DELETED, properties) + await publishEvent(Event.ACCOUNT_DELETED, properties) } -export function verified(account: Account) { +export async function verified(account: Account) { const properties = {} - publishEvent(Event.ACCOUNT_VERIFIED, properties) + await publishEvent(Event.ACCOUNT_VERIFIED, properties) } diff --git a/packages/backend-core/src/events/publishers/app.ts b/packages/backend-core/src/events/publishers/app.ts index dc8ca165fd..00df1f18bc 100644 --- a/packages/backend-core/src/events/publishers/app.ts +++ b/packages/backend-core/src/events/publishers/app.ts @@ -20,54 +20,54 @@ export const created = async (app: App) => { await publishEvent(Event.APP_CREATED, properties) } -export function updated(app: App) { +export async function updated(app: App) { const properties: AppUpdatedEvent = {} - publishEvent(Event.APP_UPDATED, properties) + await publishEvent(Event.APP_UPDATED, properties) } -export function deleted(app: App) { +export async function deleted(app: App) { const properties: AppDeletedEvent = {} - publishEvent(Event.APP_DELETED, properties) + await publishEvent(Event.APP_DELETED, properties) } -export function published(app: App) { +export async function published(app: App) { const properties: AppPublishedEvent = {} - publishEvent(Event.APP_PUBLISHED, properties) + await publishEvent(Event.APP_PUBLISHED, properties) } -export function unpublished(app: App) { +export async function unpublished(app: App) { const properties: AppUnpublishedEvent = {} - publishEvent(Event.APP_UNPUBLISHED, properties) + await publishEvent(Event.APP_UNPUBLISHED, properties) } -export function fileImported(app: App) { +export async function fileImported(app: App) { const properties: AppFileImportedEvent = {} - publishEvent(Event.APP_FILE_IMPORTED, properties) + await publishEvent(Event.APP_FILE_IMPORTED, properties) } -export function templateImported(templateKey: string) { +export async function templateImported(templateKey: string) { const properties: AppTemplateImportedEvent = { templateKey, } - publishEvent(Event.APP_TEMPLATE_IMPORTED, properties) + await publishEvent(Event.APP_TEMPLATE_IMPORTED, properties) } -export function versionUpdated(app: App) { +export async function versionUpdated(app: App) { const properties: AppVersionUpdatedEvent = {} - publishEvent(Event.APP_VERSION_UPDATED, properties) + await publishEvent(Event.APP_VERSION_UPDATED, properties) } -export function versionReverted(app: App) { +export async function versionReverted(app: App) { const properties: AppVersionRevertedEvent = {} - publishEvent(Event.APP_VERSION_REVERTED, properties) + await publishEvent(Event.APP_VERSION_REVERTED, properties) } -export function reverted(app: App) { +export async function reverted(app: App) { const properties: AppRevertedEvent = {} - publishEvent(Event.APP_REVERTED, properties) + await publishEvent(Event.APP_REVERTED, properties) } -export function exported(app: App) { +export async function exported(app: App) { const properties: AppExportedEvent = {} - publishEvent(Event.APP_EXPORTED, properties) + await publishEvent(Event.APP_EXPORTED, properties) } diff --git a/packages/backend-core/src/events/publishers/auth.ts b/packages/backend-core/src/events/publishers/auth.ts index 61a73fbfc5..32af58258d 100644 --- a/packages/backend-core/src/events/publishers/auth.ts +++ b/packages/backend-core/src/events/publishers/auth.ts @@ -11,42 +11,42 @@ import { SSOUpdatedEvent, } from "@budibase/types" -export function login(source: LoginSource) { +export async function login(source: LoginSource) { const properties: LoginEvent = { source, } - publishEvent(Event.AUTH_LOGIN, properties) + await publishEvent(Event.AUTH_LOGIN, properties) } -export function logout() { +export async function logout() { const properties: LogoutEvent = {} - publishEvent(Event.AUTH_LOGOUT, properties) + await publishEvent(Event.AUTH_LOGOUT, properties) } -export function SSOCreated(type: SSOType) { +export async function SSOCreated(type: SSOType) { const properties: SSOCreatedEvent = { type, } - publishEvent(Event.AUTH_SSO_CREATED, properties) + await publishEvent(Event.AUTH_SSO_CREATED, properties) } -export function SSOUpdated(type: SSOType) { +export async function SSOUpdated(type: SSOType) { const properties: SSOUpdatedEvent = { type, } - publishEvent(Event.AUTH_SSO_UPDATED, properties) + await publishEvent(Event.AUTH_SSO_UPDATED, properties) } -export function SSOActivated(type: SSOType) { +export async function SSOActivated(type: SSOType) { const properties: SSOActivatedEvent = { type, } - publishEvent(Event.AUTH_SSO_ACTIVATED, properties) + await publishEvent(Event.AUTH_SSO_ACTIVATED, properties) } -export function SSODeactivated(type: SSOType) { +export async function SSODeactivated(type: SSOType) { const properties: SSODeactivatedEvent = { type, } - publishEvent(Event.AUTH_SSO_DEACTIVATED, properties) + await publishEvent(Event.AUTH_SSO_DEACTIVATED, properties) } diff --git a/packages/backend-core/src/events/publishers/automation.ts b/packages/backend-core/src/events/publishers/automation.ts index dfdddc86db..2a20a90929 100644 --- a/packages/backend-core/src/events/publishers/automation.ts +++ b/packages/backend-core/src/events/publishers/automation.ts @@ -12,41 +12,41 @@ import { AutomationTriggerUpdatedEvent, } from "@budibase/types" -export function created(automation: Automation) { +export async function created(automation: Automation) { const properties: AutomationCreatedEvent = {} - publishEvent(Event.AUTOMATION_CREATED, properties) + await publishEvent(Event.AUTOMATION_CREATED, properties) } -export function deleted(automation: Automation) { +export async function deleted(automation: Automation) { const properties: AutomationDeletedEvent = {} - publishEvent(Event.AUTOMATION_DELETED, properties) + await publishEvent(Event.AUTOMATION_DELETED, properties) } -export function tested(automation: Automation) { +export async function tested(automation: Automation) { const properties: AutomationTestedEvent = {} - publishEvent(Event.AUTOMATION_TESTED, properties) + await publishEvent(Event.AUTOMATION_TESTED, properties) } -// TODO -// exports.run = () => { -// const properties = {} -// events.processEvent(Events.AUTOMATION_RUN, properties) -// } - -export function stepCreated(automation: Automation, step: AutomationStep) { +export async function stepCreated( + automation: Automation, + step: AutomationStep +) { const properties: AutomationStepCreatedEvent = {} - publishEvent(Event.AUTOMATION_STEP_CREATED, properties) + await publishEvent(Event.AUTOMATION_STEP_CREATED, properties) } -export function stepDeleted(automation: Automation, step: AutomationStep) { +export async function stepDeleted( + automation: Automation, + step: AutomationStep +) { const properties: AutomationStepDeletedEvent = {} - publishEvent(Event.AUTOMATION_STEP_DELETED, properties) + await publishEvent(Event.AUTOMATION_STEP_DELETED, properties) } -export function triggerUpdated( +export async function triggerUpdated( automation: Automation, trigger: AutomationTrigger ) { const properties: AutomationTriggerUpdatedEvent = {} - publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties) + await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties) } diff --git a/packages/backend-core/src/events/publishers/datasource.ts b/packages/backend-core/src/events/publishers/datasource.ts index 4ca4b1f9b7..e5392d3bb8 100644 --- a/packages/backend-core/src/events/publishers/datasource.ts +++ b/packages/backend-core/src/events/publishers/datasource.ts @@ -7,17 +7,17 @@ import { DatasourceDeletedEvent, } from "@budibase/types" -export function created(datasource: Datasource) { +export async function created(datasource: Datasource) { const properties: DatasourceCreatedEvent = {} - publishEvent(Event.DATASOURCE_CREATED, properties) + await publishEvent(Event.DATASOURCE_CREATED, properties) } -export function updated(datasource: Datasource) { +export async function updated(datasource: Datasource) { const properties: DatasourceUpdatedEvent = {} - publishEvent(Event.DATASOURCE_UPDATED, properties) + await publishEvent(Event.DATASOURCE_UPDATED, properties) } -export function deleted(datasource: Datasource) { +export async function deleted(datasource: Datasource) { const properties: DatasourceDeletedEvent = {} - publishEvent(Event.DATASOURCE_DELETED, properties) + await publishEvent(Event.DATASOURCE_DELETED, properties) } diff --git a/packages/backend-core/src/events/publishers/email.ts b/packages/backend-core/src/events/publishers/email.ts index 72d14120e7..76745453f9 100644 --- a/packages/backend-core/src/events/publishers/email.ts +++ b/packages/backend-core/src/events/publishers/email.ts @@ -6,12 +6,12 @@ import { SMTPUpdatedEvent, } from "@budibase/types" -export function SMTPCreated(config: SMTPConfig) { +export async function SMTPCreated(config: SMTPConfig) { const properties: SMTPCreatedEvent = {} - publishEvent(Event.EMAIL_SMTP_CREATED, properties) + await publishEvent(Event.EMAIL_SMTP_CREATED, properties) } -export function SMTPUpdated(config: SMTPConfig) { +export async function SMTPUpdated(config: SMTPConfig) { const properties: SMTPUpdatedEvent = {} - publishEvent(Event.EMAIL_SMTP_UPDATED, properties) + await publishEvent(Event.EMAIL_SMTP_UPDATED, properties) } diff --git a/packages/backend-core/src/events/publishers/layout.ts b/packages/backend-core/src/events/publishers/layout.ts index ae0129ab35..109f23571a 100644 --- a/packages/backend-core/src/events/publishers/layout.ts +++ b/packages/backend-core/src/events/publishers/layout.ts @@ -6,12 +6,12 @@ import { LayoutDeletedEvent, } from "@budibase/types" -export function created(layout: Layout) { +export async function created(layout: Layout) { const properties: LayoutCreatedEvent = {} - publishEvent(Event.LAYOUT_CREATED, properties) + await publishEvent(Event.LAYOUT_CREATED, properties) } -export function deleted(layout: Layout) { +export async function deleted(layout: Layout) { const properties: LayoutDeletedEvent = {} - publishEvent(Event.LAYOUT_DELETED, properties) + await publishEvent(Event.LAYOUT_DELETED, properties) } diff --git a/packages/backend-core/src/events/publishers/license.ts b/packages/backend-core/src/events/publishers/license.ts index 22fc19cd10..1ec6649223 100644 --- a/packages/backend-core/src/events/publishers/license.ts +++ b/packages/backend-core/src/events/publishers/license.ts @@ -10,34 +10,34 @@ import { } from "@budibase/types" // TODO -export function updgraded(license: License) { +export async function updgraded(license: License) { const properties: LicenseUpgradedEvent = {} - publishEvent(Event.LICENSE_UPGRADED, properties) + await publishEvent(Event.LICENSE_UPGRADED, properties) } // TODO -export function downgraded(license: License) { +export async function downgraded(license: License) { const properties: LicenseDowngradedEvent = {} - publishEvent(Event.LICENSE_DOWNGRADED, properties) + await publishEvent(Event.LICENSE_DOWNGRADED, properties) } // TODO -export function updated(license: License) { +export async function updated(license: License) { const properties: LicenseUpdatedEvent = {} - publishEvent(Event.LICENSE_UPDATED, properties) + await publishEvent(Event.LICENSE_UPDATED, properties) } // TODO -export function activated(license: License) { +export async function activated(license: License) { const properties: LicenseActivatedEvent = {} - publishEvent(Event.LICENSE_ACTIVATED, properties) + await publishEvent(Event.LICENSE_ACTIVATED, properties) } // TODO -export function quotaExceeded(quotaName: string, value: number) { +export async function quotaExceeded(quotaName: string, value: number) { const properties: LicenseQuotaExceededEvent = { name: quotaName, value, } - publishEvent(Event.LICENSE_QUOTA_EXCEEDED, properties) + await publishEvent(Event.LICENSE_QUOTA_EXCEEDED, properties) } diff --git a/packages/backend-core/src/events/publishers/org.ts b/packages/backend-core/src/events/publishers/org.ts index c1e5948f8a..ae2670d4da 100644 --- a/packages/backend-core/src/events/publishers/org.ts +++ b/packages/backend-core/src/events/publishers/org.ts @@ -1,30 +1,35 @@ import { publishEvent } from "../events" import { Event, VersionCheckedEvent } from "@budibase/types" -export function nameUpdated() { +export async function nameUpdated() { const properties = {} - publishEvent(Event.ORG_NAME_UPDATED, properties) + await publishEvent(Event.ORG_NAME_UPDATED, properties) } -export function logoUpdated() { +export async function logoUpdated() { const properties = {} - publishEvent(Event.ORG_LOGO_UPDATED, properties) + await publishEvent(Event.ORG_LOGO_UPDATED, properties) } -export function platformURLUpdated() { +export async function platformURLUpdated() { const properties = {} - publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties) + await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties) } -export function versionChecked(version: number) { +export async function versionChecked(version: number) { const properties: VersionCheckedEvent = { version, } - publishEvent(Event.UPDATE_VERSION_CHECKED, properties) + await publishEvent(Event.UPDATE_VERSION_CHECKED, properties) } // TODO -export function analyticsOptOut() { +export async function analyticsOptOut() { const properties = {} - publishEvent(Event.ANALYTICS_OPT_OUT, properties) + await publishEvent(Event.ANALYTICS_OPT_OUT, properties) +} + +export async function analyticsOptIn() { + const properties = {} + await publishEvent(Event.ANALYTICS_OPT_OUT, properties) } diff --git a/packages/backend-core/src/events/publishers/query.ts b/packages/backend-core/src/events/publishers/query.ts index 94e83c2fa7..e012d5c830 100644 --- a/packages/backend-core/src/events/publishers/query.ts +++ b/packages/backend-core/src/events/publishers/query.ts @@ -12,37 +12,31 @@ import { /* eslint-disable */ -export const created = (datasource: Datasource, query: Query) => { +export const created = async (datasource: Datasource, query: Query) => { const properties: QueryCreatedEvent = {} - publishEvent(Event.QUERY_CREATED, properties) + await publishEvent(Event.QUERY_CREATED, properties) } -export const updated = (datasource: Datasource, query: Query) => { +export const updated = async (datasource: Datasource, query: Query) => { const properties: QueryUpdatedEvent = {} - publishEvent(Event.QUERY_UPDATED, properties) + await publishEvent(Event.QUERY_UPDATED, properties) } -export const deleted = (datasource: Datasource, query: Query) => { +export const deleted = async (datasource: Datasource, query: Query) => { const properties: QueryDeletedEvent = {} - publishEvent(Event.QUERY_DELETED, properties) + await publishEvent(Event.QUERY_DELETED, properties) } -export const imported = ( +export const imported = async ( datasource: Datasource, importSource: any, count: any ) => { const properties: QueryImportedEvent = {} - publishEvent(Event.QUERY_IMPORT, properties) + await publishEvent(Event.QUERY_IMPORT, properties) } -// TODO -// exports.run = () => { -// const properties = {} -// events.processEvent(Events.QUERY_RUN, properties) -// } - -export const previewed = (datasource: Datasource) => { +export const previewed = async (datasource: Datasource) => { const properties: QueryPreviewedEvent = {} - publishEvent(Event.QUERY_PREVIEWED, properties) + await publishEvent(Event.QUERY_PREVIEWED, properties) } diff --git a/packages/backend-core/src/events/publishers/role.ts b/packages/backend-core/src/events/publishers/role.ts index b08d001c77..d257eadf2b 100644 --- a/packages/backend-core/src/events/publishers/role.ts +++ b/packages/backend-core/src/events/publishers/role.ts @@ -12,27 +12,27 @@ import { /* eslint-disable */ -export function created(role: Role) { +export async function created(role: Role) { const properties: RoleCreatedEvent = {} - publishEvent(Event.ROLE_CREATED, properties) + await publishEvent(Event.ROLE_CREATED, properties) } -export function updated(role: Role) { +export async function updated(role: Role) { const properties: RoleUpdatedEvent = {} - publishEvent(Event.ROLE_UPDATED, properties) + await publishEvent(Event.ROLE_UPDATED, properties) } -export function deleted(role: Role) { +export async function deleted(role: Role) { const properties: RoleDeletedEvent = {} - publishEvent(Event.ROLE_DELETED, properties) + await publishEvent(Event.ROLE_DELETED, properties) } -export function assigned(user: User, role: string) { +export async function assigned(user: User, role: string) { const properties: RoleAssignedEvent = {} - publishEvent(Event.ROLE_ASSIGNED, properties) + await publishEvent(Event.ROLE_ASSIGNED, properties) } -export function unassigned(user: User, role: string) { +export async function unassigned(user: User, role: string) { const properties: RoleUnassignedEvent = {} - publishEvent(Event.ROLE_UNASSIGNED, properties) + await publishEvent(Event.ROLE_UNASSIGNED, properties) } diff --git a/packages/backend-core/src/events/publishers/rows.ts b/packages/backend-core/src/events/publishers/rows.ts index 450a5a6495..0877b77b7a 100644 --- a/packages/backend-core/src/events/publishers/rows.ts +++ b/packages/backend-core/src/events/publishers/rows.ts @@ -9,18 +9,18 @@ import { /* eslint-disable */ -export const created = (count: number) => { +export const created = async (count: number) => { const properties: RowsCreatedEvent = { count, } - publishEvent(Event.ROWS_CREATED, properties) + await publishEvent(Event.ROWS_CREATED, properties) } -export const imported = ( +export const imported = async ( table: Table, format: RowImportFormat, count: number ) => { const properties: RowsImportedEvent = {} - publishEvent(Event.ROWS_IMPORTED, properties) + await publishEvent(Event.ROWS_IMPORTED, properties) } diff --git a/packages/backend-core/src/events/publishers/screen.ts b/packages/backend-core/src/events/publishers/screen.ts index bf5ffef811..efb7d9538f 100644 --- a/packages/backend-core/src/events/publishers/screen.ts +++ b/packages/backend-core/src/events/publishers/screen.ts @@ -6,12 +6,12 @@ import { ScreenDeletedEvent, } from "@budibase/types" -export function created(screen: Screen) { +export async function created(screen: Screen) { const properties: ScreenCreatedEvent = {} - publishEvent(Event.SCREEN_CREATED, properties) + await publishEvent(Event.SCREEN_CREATED, properties) } -export function deleted(screen: Screen) { +export async function deleted(screen: Screen) { const properties: ScreenDeletedEvent = {} - publishEvent(Event.SCREEN_DELETED, properties) + await publishEvent(Event.SCREEN_DELETED, properties) } diff --git a/packages/backend-core/src/events/publishers/serve.ts b/packages/backend-core/src/events/publishers/serve.ts index 3a61751a8b..62aaf4fb4c 100644 --- a/packages/backend-core/src/events/publishers/serve.ts +++ b/packages/backend-core/src/events/publishers/serve.ts @@ -9,17 +9,17 @@ import { /* eslint-disable */ -export function servedBuilder(version: number) { +export async function servedBuilder(version: number) { const properties: BuilderServedEvent = {} - publishEvent(Event.SERVED_BUILDER, properties) + await publishEvent(Event.SERVED_BUILDER, properties) } -export function servedApp(app: App) { +export async function servedApp(app: App) { const properties: AppServedEvent = {} - publishEvent(Event.SERVED_APP, properties) + await publishEvent(Event.SERVED_APP, properties) } -export function servedAppPreview(app: App) { +export async function servedAppPreview(app: App) { const properties: AppPreviewServedEvent = {} - publishEvent(Event.SERVED_APP_PREVIEW, properties) + await publishEvent(Event.SERVED_APP_PREVIEW, properties) } diff --git a/packages/backend-core/src/events/publishers/table.ts b/packages/backend-core/src/events/publishers/table.ts index fca966873c..cfa4b28835 100644 --- a/packages/backend-core/src/events/publishers/table.ts +++ b/packages/backend-core/src/events/publishers/table.ts @@ -13,33 +13,27 @@ import { /* eslint-disable */ -export function created(table: Table) { +export async function created(table: Table) { const properties: TableCreatedEvent = {} - publishEvent(Event.TABLE_CREATED, properties) + await publishEvent(Event.TABLE_CREATED, properties) } -export function updated(table: Table) { +export async function updated(table: Table) { const properties: TableUpdatedEvent = {} - publishEvent(Event.TABLE_UPDATED, properties) + await publishEvent(Event.TABLE_UPDATED, properties) } -export function deleted(table: Table) { +export async function deleted(table: Table) { const properties: TableDeletedEvent = {} - publishEvent(Event.TABLE_DELETED, properties) + await publishEvent(Event.TABLE_DELETED, properties) } -export function exported(table: Table, format: TableExportFormat) { +export async function exported(table: Table, format: TableExportFormat) { const properties: TableExportedEvent = {} - publishEvent(Event.TABLE_EXPORTED, properties) + await publishEvent(Event.TABLE_EXPORTED, properties) } -export function imported(table: Table, format: TableImportFormat) { +export async function imported(table: Table, format: TableImportFormat) { const properties: TableImportedEvent = {} - publishEvent(Event.TABLE_IMPORTED, properties) -} - -// TODO -export function permissionUpdated() { - const properties = {} - publishEvent(Event.TABLE_PERMISSION_UPDATED, properties) + await publishEvent(Event.TABLE_IMPORTED, properties) } diff --git a/packages/backend-core/src/events/publishers/user.ts b/packages/backend-core/src/events/publishers/user.ts index a5da10d3a7..eeea5234cb 100644 --- a/packages/backend-core/src/events/publishers/user.ts +++ b/packages/backend-core/src/events/publishers/user.ts @@ -17,73 +17,73 @@ import { /* eslint-disable */ -export function created(user: User) { +export async function created(user: User) { const properties: UserCreatedEvent = {} - publishEvent(Event.USER_CREATED, properties) + await publishEvent(Event.USER_CREATED, properties) } -export function updated(user: User) { +export async function updated(user: User) { const properties: UserUpdatedEvent = {} - publishEvent(Event.USER_UPDATED, properties) + await publishEvent(Event.USER_UPDATED, properties) } -export function deleted(user: User) { +export async function deleted(user: User) { const properties: UserDeletedEvent = {} - publishEvent(Event.USER_DELETED, properties) + await publishEvent(Event.USER_DELETED, properties) } // PERMISSIONS -export function permissionAdminAssigned(user: User) { +export async function permissionAdminAssigned(user: User) { const properties: UserPermissionAssignedEvent = {} - publishEvent(Event.USER_PERMISSION_ADMIN_ASSIGNED, properties) + await publishEvent(Event.USER_PERMISSION_ADMIN_ASSIGNED, properties) } -export function permissionAdminRemoved(user: User) { +export async function permissionAdminRemoved(user: User) { const properties: UserPermissionRemovedEvent = {} - publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties) + await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties) } -export function permissionBuilderAssigned(user: User) { +export async function permissionBuilderAssigned(user: User) { const properties: UserPermissionAssignedEvent = {} - publishEvent(Event.USER_PERMISSION_BUILDER_ASSIGNED, properties) + await publishEvent(Event.USER_PERMISSION_BUILDER_ASSIGNED, properties) } -export function permissionBuilderRemoved(user: User) { +export async function permissionBuilderRemoved(user: User) { const properties: UserPermissionRemovedEvent = {} - publishEvent(Event.USER_PERMISSION_BUILDER_REMOVED, properties) + await publishEvent(Event.USER_PERMISSION_BUILDER_REMOVED, properties) } // INVITE -export function invited(userInfo: any) { +export async function invited(userInfo: any) { const properties: UserInvitedEvent = {} - publishEvent(Event.USER_INVITED, properties) + await publishEvent(Event.USER_INVITED, properties) } -export function inviteAccepted(user: User) { +export async function inviteAccepted(user: User) { const properties: UserInviteAcceptedEvent = {} - publishEvent(Event.USER_INVITED_ACCEPTED, properties) + await publishEvent(Event.USER_INVITED_ACCEPTED, properties) } // PASSWORD -export function passwordForceReset(user: User) { +export async function passwordForceReset(user: User) { const properties: UserPasswordForceResetEvent = {} - publishEvent(Event.USER_PASSWORD_FORCE_RESET, properties) + await publishEvent(Event.USER_PASSWORD_FORCE_RESET, properties) } -export function passwordUpdated(user: User) { +export async function passwordUpdated(user: User) { const properties: UserPasswordUpdatedEvent = {} - publishEvent(Event.USER_PASSWORD_UPDATED, properties) + await publishEvent(Event.USER_PASSWORD_UPDATED, properties) } -export function passwordResetRequested(user: User) { +export async function passwordResetRequested(user: User) { const properties: UserPasswordResetRequestedEvent = {} - publishEvent(Event.USER_PASSWORD_RESET_REQUESTED, properties) + await publishEvent(Event.USER_PASSWORD_RESET_REQUESTED, properties) } -export function passwordReset(user: User) { +export async function passwordReset(user: User) { const properties: UserPasswordResetEvent = {} - publishEvent(Event.USER_PASSWORD_RESET, properties) + await publishEvent(Event.USER_PASSWORD_RESET, properties) } diff --git a/packages/backend-core/src/events/publishers/view.ts b/packages/backend-core/src/events/publishers/view.ts index e9c594e8c9..ff0c8a7f0d 100644 --- a/packages/backend-core/src/events/publishers/view.ts +++ b/packages/backend-core/src/events/publishers/view.ts @@ -19,52 +19,52 @@ import { /* eslint-disable */ -export function created(view: View) { +export async function created(view: View) { const properties: ViewCreatedEvent = {} - publishEvent(Event.VIEW_CREATED, properties) + await publishEvent(Event.VIEW_CREATED, properties) } -export function updated(view: View) { +export async function updated(view: View) { const properties: ViewUpdatedEvent = {} - publishEvent(Event.VIEW_UPDATED, properties) + await publishEvent(Event.VIEW_UPDATED, properties) } -export function deleted() { +export async function deleted() { const properties: ViewDeletedEvent = {} - publishEvent(Event.VIEW_DELETED, properties) + await publishEvent(Event.VIEW_DELETED, properties) } -export function exported(table: Table, format: TableExportFormat) { +export async function exported(table: Table, format: TableExportFormat) { const properties: ViewExportedEvent = {} - publishEvent(Event.VIEW_EXPORTED, properties) + await publishEvent(Event.VIEW_EXPORTED, properties) } -export function filterCreated() { +export async function filterCreated() { const properties: ViewFilterCreatedEvent = {} - publishEvent(Event.VIEW_FILTER_CREATED, properties) + await publishEvent(Event.VIEW_FILTER_CREATED, properties) } -export function filterUpdated() { +export async function filterUpdated() { const properties: ViewFilterUpdatedEvent = {} - publishEvent(Event.VIEW_FILTER_UPDATED, properties) + await publishEvent(Event.VIEW_FILTER_UPDATED, properties) } -export function filterDeleted() { +export async function filterDeleted() { const properties: ViewFilterDeletedEvent = {} - publishEvent(Event.VIEW_FILTER_DELETED, properties) + await publishEvent(Event.VIEW_FILTER_DELETED, properties) } -export function calculationCreated(calculation: ViewCalculation) { +export async function calculationCreated(calculation: ViewCalculation) { const properties: ViewCalculationCreatedEvent = {} - publishEvent(Event.VIEW_CALCULATION_CREATED, properties) + await publishEvent(Event.VIEW_CALCULATION_CREATED, properties) } -export function calculationUpdated() { +export async function calculationUpdated() { const properties: ViewCalculationUpdatedEvent = {} - publishEvent(Event.VIEW_CALCULATION_UPDATED, properties) + await publishEvent(Event.VIEW_CALCULATION_UPDATED, properties) } -export function calculationDeleted() { +export async function calculationDeleted() { const properties: ViewCalculationDeletedEvent = {} - publishEvent(Event.VIEW_CALCULATION_DELETED, properties) + await publishEvent(Event.VIEW_CALCULATION_DELETED, properties) } diff --git a/packages/backend-core/src/middleware/authenticated.js b/packages/backend-core/src/middleware/authenticated.js index ef982c799b..a1bb0a8ef1 100644 --- a/packages/backend-core/src/middleware/authenticated.js +++ b/packages/backend-core/src/middleware/authenticated.js @@ -7,6 +7,7 @@ const env = require("../environment") const { SEPARATOR, ViewNames, queryGlobalView } = require("../../db") const { getGlobalDB, doInTenant } = require("../tenancy") const { decrypt } = require("../security/encryption") +const context = require("../context") function finalise( ctx, @@ -132,7 +133,12 @@ module.exports = ( } // isAuthenticated is a function, so use a variable to be able to check authed state finalise(ctx, { authenticated, user, internal, version, publicEndpoint }) - return next() + + if (user && user.email) { + return context.doInUserContext(user, next) + } else { + return next + } } catch (err) { // invalid token, clear the cookie if (err && err.name === "JsonWebTokenError") { @@ -141,7 +147,7 @@ module.exports = ( // allow configuring for public access if ((opts && opts.publicAllowed) || publicEndpoint) { finalise(ctx, { authenticated: false, version, publicEndpoint }) - return next() + return context.doInUserContext({ _id: "public_user" }, next) } else { ctx.throw(err.status || 403, err) } diff --git a/packages/backend-core/src/tests/utilities/mocks/events.js b/packages/backend-core/src/tests/utilities/mocks/events.js index 8f660286cc..86bfda2dbe 100644 --- a/packages/backend-core/src/tests/utilities/mocks/events.js +++ b/packages/backend-core/src/tests/utilities/mocks/events.js @@ -1,6 +1,8 @@ jest.mock("../../../events", () => { return { - analyticsEnabled: () => false, + analytics: { + enabled: () => false, + }, shutdown: () => {}, account: { created: jest.fn(), diff --git a/packages/backend-core/src/utils.js b/packages/backend-core/src/utils.js index bb8d1d4805..9d2524bbeb 100644 --- a/packages/backend-core/src/utils.js +++ b/packages/backend-core/src/utils.js @@ -194,6 +194,6 @@ exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => { userId, sessions.map(({ sessionId }) => sessionId) ) - events.auth.logout() + await events.auth.logout() await userCache.invalidateUser(userId) } diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index d10990573a..d858801990 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -8,7 +8,7 @@ const SERVER_PORT = cypressConfig.env.PORT const WORKER_PORT = cypressConfig.env.WORKER_PORT process.env.NODE_ENV = "cypress" -process.env.ENABLE_ANALYTICS = "false" +process.env.ENABLE_ANALYTICS = "0" process.env.JWT_SECRET = cypressConfig.env.JWT_SECRET process.env.COUCH_URL = `leveldb://${tmpdir}/.data/` process.env.SELF_HOSTED = 1 diff --git a/packages/builder/src/pages/builder/portal/settings/organisation.svelte b/packages/builder/src/pages/builder/portal/settings/organisation.svelte index c13b1dc1eb..8c091ce952 100644 --- a/packages/builder/src/pages/builder/portal/settings/organisation.svelte +++ b/packages/builder/src/pages/builder/portal/settings/organisation.svelte @@ -130,7 +130,7 @@ Analytics - Choose whether to opt-in or opt-out of analtics + Choose whether to opt-in or opt-out of analytics.
diff --git a/packages/server/package.json b/packages/server/package.json index 3468b5d6ae..fdaecef212 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -145,7 +145,7 @@ "@babel/core": "^7.14.3", "@babel/preset-env": "^7.14.4", "@budibase/standard-components": "^0.9.139", - "@budibase/types": "^1.0.126-alpha.0", + "@budibase/types": "^1.0.167-alpha.8", "@jest/test-sequencer": "^24.8.0", "@types/apidoc": "^0.50.0", "@types/bson": "^4.2.0", diff --git a/packages/server/scripts/likeCypress.ts b/packages/server/scripts/likeCypress.ts index ac32608a32..6e9f763635 100644 --- a/packages/server/scripts/likeCypress.ts +++ b/packages/server/scripts/likeCypress.ts @@ -10,7 +10,7 @@ const WORKER_PORT = "4200" // @ts-ignore process.env.NODE_ENV = "cypress" -process.env.ENABLE_ANALYTICS = "false" +process.env.ENABLE_ANALYTICS = "0" process.env.JWT_SECRET = "budibase" process.env.COUCH_URL = `leveldb://${tmpdir}/.data/` process.env.SELF_HOSTED = "1" diff --git a/packages/server/src/api/controllers/analytics.ts b/packages/server/src/api/controllers/analytics.ts index 9d0329bd04..e8fa8d82fb 100644 --- a/packages/server/src/api/controllers/analytics.ts +++ b/packages/server/src/api/controllers/analytics.ts @@ -2,6 +2,6 @@ import { events } from "@budibase/backend-core" export const isEnabled = async (ctx: any) => { ctx.body = { - enabled: events.analyticsEnabled(), + enabled: events.analytics.enabled(), } } diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index a9679f959a..221df7f0dd 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -292,14 +292,14 @@ const performAppCreate = async (ctx: any) => { return newApplication } -const creationEvents = (request: any, app: App) => { - let creationFns = [] +const creationEvents = async (request: any, app: App) => { + let creationFns: ((app: App) => Promise)[] = [] const body = request.body if (body.useTemplate === "true") { // from template if (body.templateKey) { - creationFns.push(() => events.app.templateImported(body.templateKey)) + creationFns.push(app => events.app.templateImported(body.templateKey)) } // from file else if (request.files?.templateFile) { @@ -313,12 +313,12 @@ const creationEvents = (request: any, app: App) => { creationFns.push(events.app.created) for (let fn of creationFns) { - fn(app) + await fn(app) } } const appPostCreate = async (ctx: any, app: App) => { - creationEvents(ctx.request, app) + await creationEvents(ctx.request, app) // app import & template creation if (ctx.request.body.useTemplate === "true") { const rows = await getUniqueRows([app.appId]) @@ -363,7 +363,7 @@ export const update = async (ctx: any) => { } const app = await updateAppPackage(ctx.request.body, ctx.params.appId) - events.app.updated(app) + await events.app.updated(app) ctx.status = 200 ctx.body = app } @@ -386,7 +386,7 @@ export const updateClient = async (ctx: any) => { revertableVersion: currentVersion, } const app = await updateAppPackage(appPackageUpdates, ctx.params.appId) - events.app.versionUpdated(app) + await events.app.versionUpdated(app) ctx.status = 200 ctx.body = app } @@ -410,7 +410,7 @@ export const revertClient = async (ctx: any) => { revertableVersion: null, } const app = await updateAppPackage(appPackageUpdates, ctx.params.appId) - events.app.versionReverted(app) + await events.app.versionReverted(app) ctx.status = 200 ctx.body = app } @@ -429,10 +429,10 @@ const destroyApp = async (ctx: any) => { if (isUnpublish) { await quotas.removePublishedApp() - events.app.unpublished(app) + await events.app.unpublished(app) } else { await quotas.removeApp() - events.app.deleted(app) + await events.app.deleted(app) } /* istanbul ignore next */ diff --git a/packages/server/src/api/controllers/automation.js b/packages/server/src/api/controllers/automation.js index 2c4c669392..ddea76beb4 100644 --- a/packages/server/src/api/controllers/automation.js +++ b/packages/server/src/api/controllers/automation.js @@ -71,9 +71,9 @@ exports.create = async function (ctx) { newAuto: automation, }) const response = await db.put(automation) - events.automation.created() + await events.automation.created() for (let step of automation.definition.steps) { - events.automation.stepCreated(step) + await events.automation.stepCreated(step) } automation._rev = response.rev @@ -97,19 +97,20 @@ const getDeletedSteps = (oldAutomation, automation) => { return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id)) } -const handleStepEvents = (oldAutomation, automation) => { +const handleStepEvents = async (oldAutomation, automation) => { // new steps const newSteps = getNewSteps(oldAutomation, automation) for (let step of newSteps) { - events.automation.stepCreated(step) + await events.automation.stepCreated(step) } // old steps const deletedSteps = getDeletedSteps(oldAutomation, automation) for (let step of deletedSteps) { - events.automation.stepDeleted(step) + await events.automation.stepDeleted(step) } } + exports.update = async function (ctx) { const db = getAppDB() let automation = ctx.request.body @@ -133,7 +134,7 @@ exports.update = async function (ctx) { : {} // trigger has been updated, remove the test inputs if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) { - events.automation.triggerUpdated() + await events.automation.triggerUpdated() await deleteEntityMetadata( ctx.appId, MetadataTypes.AUTOMATION_TEST_INPUT, @@ -141,7 +142,7 @@ exports.update = async function (ctx) { ) } - handleStepEvents(oldAutomation, automation) + await handleStepEvents(oldAutomation, automation) ctx.status = 200 ctx.body = { @@ -179,7 +180,7 @@ exports.destroy = async function (ctx) { // delete metadata first await cleanupAutomationMetadata(automationId) ctx.body = await db.remove(automationId, ctx.params.rev) - events.automation.deleted() + await events.automation.deleted() } exports.getActionList = async function (ctx) { @@ -247,5 +248,5 @@ exports.test = async function (ctx) { }) await clearTestFlag(automation._id) ctx.body = response - events.automation.tested() + await events.automation.tested() } diff --git a/packages/server/src/api/controllers/backup.js b/packages/server/src/api/controllers/backup.js index 193f4139c5..a6b7adf98a 100644 --- a/packages/server/src/api/controllers/backup.js +++ b/packages/server/src/api/controllers/backup.js @@ -7,5 +7,5 @@ exports.exportAppDump = async function (ctx) { const backupIdentifier = `${appName}-export-${new Date().getTime()}.txt` ctx.attachment(backupIdentifier) ctx.body = await streamBackup(appId) - events.app.exported() + await events.app.exported() } diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index d9e9dda046..63c51fb92c 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -109,7 +109,7 @@ exports.update = async function (ctx) { } const response = await db.put(datasource) - events.datasource.updated() + await events.datasource.updated() datasource._rev = response.rev // Drain connection pools when configuration is changed @@ -144,7 +144,7 @@ exports.save = async function (ctx) { } const dbResp = await db.put(datasource) - events.datasource.created() + await events.datasource.created() datasource._rev = dbResp.rev // Drain connection pools when configuration is changed @@ -179,7 +179,7 @@ exports.destroy = async function (ctx) { // delete the datasource await db.remove(ctx.params.datasourceId, ctx.params.revId) - events.datasource.deleted() + await events.datasource.deleted() ctx.message = `Datasource deleted.` ctx.status = 200 diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 3520fc9f02..7c1a093398 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -195,7 +195,7 @@ const _deployApp = async function (ctx: any) { app = await deployApp(deployment) } - events.app.published(app) + await events.app.published(app) ctx.body = deployment } diff --git a/packages/server/src/api/controllers/dev.js b/packages/server/src/api/controllers/dev.js index d59a9660fc..1146013c3b 100644 --- a/packages/server/src/api/controllers/dev.js +++ b/packages/server/src/api/controllers/dev.js @@ -118,7 +118,7 @@ exports.revert = async ctx => { ctx.body = { message: "Reverted changes successfully.", } - events.app.reverted() + await events.app.reverted() } catch (err) { ctx.throw(400, `Unable to revert. ${err}`) } finally { diff --git a/packages/server/src/api/controllers/layout.js b/packages/server/src/api/controllers/layout.js index 1809fce344..044d4a1acb 100644 --- a/packages/server/src/api/controllers/layout.js +++ b/packages/server/src/api/controllers/layout.js @@ -20,7 +20,7 @@ exports.save = async function (ctx) { layout._id = layout._id || generateLayoutID() const response = await db.put(layout) - events.layout.created() + await events.layout.created() layout._rev = response.rev ctx.body = layout @@ -48,7 +48,7 @@ exports.destroy = async function (ctx) { } await db.remove(layoutId, layoutRev) - events.layout.deleted() + await events.layout.deleted() ctx.body = { message: "Layout deleted successfully" } ctx.status = 200 } diff --git a/packages/server/src/api/controllers/query/import/index.ts b/packages/server/src/api/controllers/query/import/index.ts index eb70a33b2f..339775cbdc 100644 --- a/packages/server/src/api/controllers/query/import/index.ts +++ b/packages/server/src/api/controllers/query/import/index.ts @@ -84,9 +84,9 @@ export class RestImporter { const count = successQueries.length const importSource = this.source.getImportSource() const datasource: Datasource = await db.get(datasourceId) - events.query.imported(datasource, importSource, count) + await events.query.imported(datasource, importSource, count) for (let query of successQueries) { - events.query.created(datasource, query) + await events.query.created(datasource, query) } return { diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index a9bbdcf53c..ff101d48a7 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -92,7 +92,7 @@ export async function save(ctx: any) { } const response = await db.put(query) - eventFn() + await eventFn() query._rev = response.rev ctx.body = query @@ -132,7 +132,7 @@ export async function preview(ctx: any) { }) const { rows, keys, info, extra } = await quotas.addQuery(runFn) - events.query.previewed(datasource) + await events.query.previewed(datasource) ctx.body = { rows, schemaFields: [...new Set(keys)], @@ -223,5 +223,5 @@ export async function destroy(ctx: any) { await db.remove(ctx.params.queryId, ctx.params.revId) ctx.message = `Query deleted.` ctx.status = 200 - events.query.deleted(datasource, query) + await events.query.deleted(datasource, query) } diff --git a/packages/server/src/api/controllers/role.js b/packages/server/src/api/controllers/role.js index 8f28847266..9a406ad63f 100644 --- a/packages/server/src/api/controllers/role.js +++ b/packages/server/src/api/controllers/role.js @@ -66,9 +66,9 @@ exports.save = async function (ctx) { } const result = await db.put(role) if (isCreate) { - events.role.created(role) + await events.role.created(role) } else { - events.role.updated(role) + await events.role.updated(role) } await updateRolesOnUserTable(db, _id, UpdateRolesOptions.CREATED) role._rev = result.rev @@ -97,7 +97,7 @@ exports.destroy = async function (ctx) { } await db.remove(roleId, ctx.params.rev) - events.role.deleted(role) + await events.role.deleted(role) await updateRolesOnUserTable( db, ctx.params.roleId, diff --git a/packages/server/src/api/controllers/screen.js b/packages/server/src/api/controllers/screen.js index 01e6a22611..dd96493e5b 100644 --- a/packages/server/src/api/controllers/screen.js +++ b/packages/server/src/api/controllers/screen.js @@ -33,7 +33,7 @@ exports.save = async ctx => { const response = await db.put(screen) if (eventFn) { - eventFn(screen) + await eventFn(screen) } ctx.message = `Screen ${screen.name} saved.` ctx.body = { @@ -50,7 +50,7 @@ exports.destroy = async ctx => { await db.remove(id, ctx.params.screenRev) - events.screen.deleted(screen) + await events.screen.deleted(screen) ctx.body = { message: "Screen deleted successfully", } diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js index bcd12172dd..07ad691faa 100644 --- a/packages/server/src/api/controllers/static/index.js +++ b/packages/server/src/api/controllers/static/index.js @@ -43,7 +43,7 @@ async function prepareUpload({ s3Key, bucket, metadata, file }) { exports.serveBuilder = async function (ctx) { let builderPath = resolve(TOP_LEVEL_PATH, "builder") await send(ctx, ctx.file, { root: builderPath }) - events.serve.servedBuilder(version) + await events.serve.servedBuilder(version) } exports.uploadFile = async function (ctx) { @@ -94,9 +94,9 @@ exports.serveApp = async function (ctx) { } if (isDevAppID(appInfo.appId)) { - events.serve.servedAppPreview(appInfo) + await events.serve.servedAppPreview(appInfo) } else { - events.serve.servedApp(appInfo) + await events.serve.servedApp(appInfo) } } diff --git a/packages/server/src/api/controllers/table/index.js b/packages/server/src/api/controllers/table/index.js index 701b805b50..e6192457af 100644 --- a/packages/server/src/api/controllers/table/index.js +++ b/packages/server/src/api/controllers/table/index.js @@ -60,12 +60,12 @@ exports.save = async function (ctx) { table.dataImport && table.dataImport.csvString ? "csv" : undefined const savedTable = await pickApi({ table }).save(ctx) if (!table._id) { - events.table.created(savedTable) + await events.table.created(savedTable) } else { - events.table.updated(savedTable) + await events.table.updated(savedTable) } if (importFormat) { - events.table.imported(savedTable, importFormat) + await events.table.imported(savedTable, importFormat) } ctx.status = 200 ctx.message = `Table ${table.name} saved successfully.` @@ -78,7 +78,7 @@ exports.destroy = async function (ctx) { const appId = ctx.appId const tableId = ctx.params.tableId const deletedTable = await pickApi({ tableId }).destroy(ctx) - events.table.deleted(deletedTable) + await events.table.deleted(deletedTable) ctx.eventEmitter && ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable) ctx.status = 200 diff --git a/packages/server/src/api/controllers/table/utils.ts b/packages/server/src/api/controllers/table/utils.ts index 31fd1d4220..896221dddf 100644 --- a/packages/server/src/api/controllers/table/utils.ts +++ b/packages/server/src/api/controllers/table/utils.ts @@ -149,7 +149,7 @@ export async function handleDataImport(user: any, table: any, dataImport: any) { } await quotas.addRows(finalData.length, () => db.bulkDocs(finalData)) - events.rows.imported(table, "csv", finalData.length) + await events.rows.imported(table, "csv", finalData.length) return table } diff --git a/packages/server/src/api/controllers/view/index.js b/packages/server/src/api/controllers/view/index.js index 16d30d350d..404652a8db 100644 --- a/packages/server/src/api/controllers/view/index.js +++ b/packages/server/src/api/controllers/view/index.js @@ -39,7 +39,7 @@ exports.save = async ctx => { existingTable.views[viewName] = existingTable.views[originalName] } await db.put(table) - handleViewEvents(existingTable.views[viewName], table.views[viewName]) + await handleViewEvents(existingTable.views[viewName], table.views[viewName]) ctx.body = { ...table.views[viewToSave.name], @@ -47,16 +47,16 @@ exports.save = async ctx => { } } -const calculationEvents = (existingView, newView) => { +const calculationEvents = async (existingView, newView) => { const existingCalculation = existingView && existingView.calculation const newCalculation = newView && newView.calculation if (existingCalculation && !newCalculation) { - events.view.calculationDeleted() + await events.view.calculationDeleted() } if (!existingCalculation && newCalculation) { - events.view.calculationCreated() + await events.view.calculationCreated() } if ( @@ -64,11 +64,11 @@ const calculationEvents = (existingView, newView) => { newCalculation && existingCalculation !== newCalculation ) { - events.view.calculationUpdated() + await events.view.calculationUpdated() } } -const filterEvents = (existingView, newView) => { +const filterEvents = async (existingView, newView) => { const hasExistingFilters = !!( existingView && existingView.filters && @@ -77,11 +77,11 @@ const filterEvents = (existingView, newView) => { const hasNewFilters = !!(newView && newView.filters && newView.filters.length) if (hasExistingFilters && !hasNewFilters) { - events.view.filterDeleted() + await events.view.filterDeleted() } if (!hasExistingFilters && hasNewFilters) { - events.view.filterCreated() + await events.view.filterCreated() } if ( @@ -89,18 +89,18 @@ const filterEvents = (existingView, newView) => { hasNewFilters && !isEqual(existingView.filters, newView.filters) ) { - events.view.filterUpdated() + await events.view.filterUpdated() } } -const handleViewEvents = (existingView, newView) => { +const handleViewEvents = async (existingView, newView) => { if (!existingView) { - events.view.created() + await events.view.created() } else { - events.view.updated() + await events.view.updated() } - calculationEvents(existingView, newView) - filterEvents(existingView, newView) + await calculationEvents(existingView, newView) + await filterEvents(existingView, newView) } exports.destroy = async ctx => { @@ -110,7 +110,7 @@ exports.destroy = async ctx => { const table = await db.get(view.meta.tableId) delete table.views[viewName] await db.put(table) - events.view.deleted() + await events.view.deleted() ctx.body = view } @@ -182,8 +182,8 @@ exports.exportView = async ctx => { ctx.body = apiFileReturn(exporter(headers, rows)) if (viewName.startsWith(DocumentTypes.TABLE)) { - events.table.exported(table, format) + await events.table.exported(table, format) } else { - events.view.exported(table, format) + await events.view.exported(table, format) } } diff --git a/packages/server/src/migrations/functions/backfill/app/apps.ts b/packages/server/src/migrations/functions/backfill/app/apps.ts index 0099f04290..35536198aa 100644 --- a/packages/server/src/migrations/functions/backfill/app/apps.ts +++ b/packages/server/src/migrations/functions/backfill/app/apps.ts @@ -5,10 +5,10 @@ export const backfill = async (appDb: any) => { const app: App = await appDb.get(db.DocumentTypes.APP_METADATA) if (db.isDevAppID(app.appId)) { - events.app.created(app) + await events.app.created(app) } if (db.isProdAppID(app.appId)) { - events.app.published(app) + await events.app.published(app) } } diff --git a/packages/server/src/migrations/functions/backfill/app/automations.ts b/packages/server/src/migrations/functions/backfill/app/automations.ts index 1c1f0e1da4..ccdc1cbdb0 100644 --- a/packages/server/src/migrations/functions/backfill/app/automations.ts +++ b/packages/server/src/migrations/functions/backfill/app/automations.ts @@ -16,10 +16,10 @@ export const backfill = async (appDb: any) => { const automations = await getAutomations(appDb) for (const automation of automations) { - events.automation.created(automation) + await events.automation.created(automation) for (const step of automation.definition.steps) { - events.automation.stepCreated(automation, step) + await events.automation.stepCreated(automation, step) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/datasources.ts b/packages/server/src/migrations/functions/backfill/app/datasources.ts index 7ebc92ab7c..c1ad9d02e3 100644 --- a/packages/server/src/migrations/functions/backfill/app/datasources.ts +++ b/packages/server/src/migrations/functions/backfill/app/datasources.ts @@ -16,7 +16,7 @@ export const backfill = async (appDb: any) => { const datasources: Datasource[] = await getDatasources(appDb) for (const datasource of datasources) { - events.datasource.created(datasource) + await events.datasource.created(datasource) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/layouts.ts b/packages/server/src/migrations/functions/backfill/app/layouts.ts index 89c3aa9dc2..fb0db1b5a6 100644 --- a/packages/server/src/migrations/functions/backfill/app/layouts.ts +++ b/packages/server/src/migrations/functions/backfill/app/layouts.ts @@ -16,7 +16,7 @@ export const backfill = async (appDb: any) => { const layouts: Layout[] = await getLayouts(appDb) for (const layout of layouts) { - events.layout.created(layout) + await events.layout.created(layout) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/queries.ts b/packages/server/src/migrations/functions/backfill/app/queries.ts index 6c6ad985f2..dfc236ec8b 100644 --- a/packages/server/src/migrations/functions/backfill/app/queries.ts +++ b/packages/server/src/migrations/functions/backfill/app/queries.ts @@ -27,7 +27,7 @@ export const backfill = async (appDb: any) => { appDb, query.datasourceId ) - events.query.created(datasource, query) + await events.query.created(datasource, query) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/roles.ts b/packages/server/src/migrations/functions/backfill/app/roles.ts index de2ce9d37b..4672030b55 100644 --- a/packages/server/src/migrations/functions/backfill/app/roles.ts +++ b/packages/server/src/migrations/functions/backfill/app/roles.ts @@ -16,7 +16,7 @@ export const backfill = async (appDb: any) => { const roles = await getRoles(appDb) for (const role of roles) { - events.role.created(role) + await events.role.created(role) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/screens.ts b/packages/server/src/migrations/functions/backfill/app/screens.ts index d2fe0bd99b..340187ae40 100644 --- a/packages/server/src/migrations/functions/backfill/app/screens.ts +++ b/packages/server/src/migrations/functions/backfill/app/screens.ts @@ -16,7 +16,7 @@ export const backfill = async (appDb: any) => { const screens = await getScreens(appDb) for (const screen of screens) { - events.screen.created(screen) + await events.screen.created(screen) } } } diff --git a/packages/server/src/migrations/functions/backfill/app/tables.ts b/packages/server/src/migrations/functions/backfill/app/tables.ts index 4231875190..c7401e921d 100644 --- a/packages/server/src/migrations/functions/backfill/app/tables.ts +++ b/packages/server/src/migrations/functions/backfill/app/tables.ts @@ -16,18 +16,18 @@ export const backfill = async (appDb: any) => { const tables = await getTables(appDb) for (const table of tables) { - events.table.created(table) + await events.table.created(table) if (table.views) { for (const view of Object.values(table.views)) { - events.view.created(view) + await events.view.created(view) if (view.calculation) { - events.view.calculationCreated(view.calculation) + await events.view.calculationCreated(view.calculation) } if (view.filters?.length) { - events.view.filterCreated() + await events.view.filterCreated() } } } diff --git a/packages/server/src/migrations/functions/backfill/global/configs.ts b/packages/server/src/migrations/functions/backfill/global/configs.ts index 7b04cbc05f..5c3644fca5 100644 --- a/packages/server/src/migrations/functions/backfill/global/configs.ts +++ b/packages/server/src/migrations/functions/backfill/global/configs.ts @@ -25,16 +25,16 @@ export const backfill = async (globalDb: any) => { for (const config of configs) { if (isSMTPConfig(config)) { - events.email.SMTPCreated(config) + await events.email.SMTPCreated(config) } if (isGoogleConfig(config)) { - events.auth.SSOCreated("google") + await events.auth.SSOCreated("google") if (config.config.activated) { - events.auth.SSOActivated("google") + await events.auth.SSOActivated("google") } } if (isOIDCConfig(config)) { - events.auth.SSOCreated("oidc") + await events.auth.SSOCreated("oidc") if (config.config.configs[0].activated) { events.auth.SSOActivated("oidc") } @@ -42,12 +42,12 @@ export const backfill = async (globalDb: any) => { if (isSettingsConfig(config)) { const company = config.config.company if (company && company !== "Budibase") { - events.org.nameUpdated() + await events.org.nameUpdated() } const logoUrl = config.config.logoUrl if (logoUrl) { - events.org.logoUpdated() + await events.org.logoUpdated() } const platformUrl = config.config.platformUrl @@ -56,7 +56,7 @@ export const backfill = async (globalDb: any) => { platformUrl !== "http://localhost:10000" && env.SELF_HOSTED ) { - events.org.platformURLUpdated() + await events.org.platformURLUpdated() } } } diff --git a/packages/server/src/migrations/functions/backfill/global/rows.ts b/packages/server/src/migrations/functions/backfill/global/rows.ts index 593b0516d0..4aaa47c1ee 100644 --- a/packages/server/src/migrations/functions/backfill/global/rows.ts +++ b/packages/server/src/migrations/functions/backfill/global/rows.ts @@ -11,6 +11,6 @@ export const backfill = async () => { const rows: Row[] = await getUniqueRows(appIds) const rowCount = rows ? rows.length : 0 if (rowCount) { - events.rows.created(rowCount) + await events.rows.created(rowCount) } } diff --git a/packages/server/src/migrations/functions/backfill/global/users.ts b/packages/server/src/migrations/functions/backfill/global/users.ts index a3c8ce52cc..60ae9c699c 100644 --- a/packages/server/src/migrations/functions/backfill/global/users.ts +++ b/packages/server/src/migrations/functions/backfill/global/users.ts @@ -19,19 +19,19 @@ export const backfill = async (globalDb: any) => { const users = await getUsers(globalDb) for (const user of users) { - events.user.created(user) + await events.user.created(user) if (user.admin?.global) { - events.user.permissionAdminAssigned(user) + await events.user.permissionAdminAssigned(user) } if (user.builder?.global) { - events.user.permissionBuilderAssigned(user) + await events.user.permissionBuilderAssigned(user) } if (user.roles) { for (const [appId, role] of Object.entries(user.roles)) { - events.role.assigned(user, role) + await events.role.assigned(user, role) } } } diff --git a/packages/types/package.json b/packages/types/package.json index 2b73c142c1..6841478d4b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "1.0.126-alpha.0", + "version": "1.0.167-alpha.8", "description": "Budibase types", "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/types/src/core/index.ts b/packages/types/src/core/index.ts index 11d05c91f4..23d772467a 100644 --- a/packages/types/src/core/index.ts +++ b/packages/types/src/core/index.ts @@ -1 +1,2 @@ export * from "./hosting" +export * from "./sessions" diff --git a/packages/types/src/core/sessions.ts b/packages/types/src/core/sessions.ts new file mode 100644 index 0000000000..a47fd90223 --- /dev/null +++ b/packages/types/src/core/sessions.ts @@ -0,0 +1,36 @@ +import { User, Account } from "../documents" +import { Hosting } from "./hosting" + +/** + * Account portal user session. Used for self hosted accounts only. + */ +export interface AccountUserSession { + _id: string + email: string + tenantId: string + accountPortalAccess: boolean + account: Account +} + +/** + * Budibase user session. + */ +export interface BudibaseUserSession extends User { + _id: string // overwrite potentially undefined + account?: Account + accountPortalAccess?: boolean +} + +export const isAccountSession = ( + user: AccountUserSession | BudibaseUserSession +): user is AccountUserSession => { + return user.account?.hosting === Hosting.SELF +} + +export const isUserSession = ( + user: AccountUserSession | BudibaseUserSession +): user is BudibaseUserSession => { + return !user.account || user.account?.hosting === Hosting.CLOUD +} + +export type SessionUser = AccountUserSession | BudibaseUserSession diff --git a/packages/types/src/documents/account/account.ts b/packages/types/src/documents/account/account.ts index 98d6235f03..a31ccda59f 100644 --- a/packages/types/src/documents/account/account.ts +++ b/packages/types/src/documents/account/account.ts @@ -1,7 +1,82 @@ import { Hosting } from "../../core" -export interface Account { - accountId: string +export interface CreateAccount { + email: string + tenantId: string hosting: Hosting - verified: boolean + authType: AuthType + // optional fields - for sso based sign ups + registrationStep?: string + // profile + tenantName?: string + name?: string + size?: string + profession?: string +} + +export interface CreatePassswordAccount extends CreateAccount { + password: string +} + +export const isCreatePasswordAccount = ( + account: CreateAccount +): account is CreatePassswordAccount => account.authType === AuthType.PASSWORD + +export interface UpdateAccount { + stripeCustomerId?: string + licenseKey?: string +} + +export interface Account extends CreateAccount { + // generated + accountId: string + createdAt: number + // registration + verified: boolean + verificationSent: boolean + // licensing + tier: string // deprecated + stripeCustomerId?: string + licenseKey?: string +} + +export interface PasswordAccount extends Account { + password: string +} + +export const isPasswordAccount = ( + account: Account +): account is PasswordAccount => + account.authType === AuthType.PASSWORD && account.hosting === Hosting.SELF + +export interface CloudAccount extends Account { + password?: string + budibaseUserId: string +} + +export const isCloudAccount = (account: Account): account is CloudAccount => + account.hosting === Hosting.CLOUD + +export const isSelfHostAccount = (account: Account) => + account.hosting === Hosting.SELF + +export const isSSOAccount = (account: Account): account is SSOAccount => + account.authType === AuthType.SSO + +export interface SSOAccount extends Account { + pictureUrl?: string + provider?: string + providerType?: string + oauth2?: OAuthTokens + thirdPartyProfile: any // TODO: define what the google profile looks like +} + +export enum AuthType { + SSO = "sso", + PASSWORD = "password", +} + +export interface OAuthTokens { + accessToken: string + refreshToken: string } diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index 37155dcb73..1cf3025ed9 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -8,6 +8,8 @@ export interface User extends Document { admin?: { global: boolean } + providerType?: string + tenantId: string } export interface UserRoles { diff --git a/packages/types/src/events/event.ts b/packages/types/src/events/event.ts index 7838f0e45e..e4d6b40d6e 100644 --- a/packages/types/src/events/event.ts +++ b/packages/types/src/events/event.ts @@ -42,6 +42,7 @@ export enum Event { // ORG / ANALYTICS ANALYTICS_OPT_OUT = "analytics:opt:out", + ANALYTICS_OPT_IN = "analytics:opt:in", // APP APP_CREATED = "app:created", @@ -88,7 +89,6 @@ export enum Event { TABLE_EXPORTED = "table:exported", TABLE_IMPORTED = "table:imported", TABLE_DATA_IMPORTED = "table:data:imported", - TABLE_PERMISSION_UPDATED = "table:permission:updated", // VIEW VIEW_CREATED = "view:created", @@ -140,12 +140,6 @@ export enum Event { ACCOUNT_VERIFIED = "account:verified", } -export enum IdentityType { - TENANT = "tenant", - USER = "user", - ACCOUNT = "account", -} - export type RowImportFormat = "csv" export type TableExportFormat = "json" | "csv" export type TableImportFormat = "csv" diff --git a/packages/types/src/events/identification.ts b/packages/types/src/events/identification.ts new file mode 100644 index 0000000000..0429882ecd --- /dev/null +++ b/packages/types/src/events/identification.ts @@ -0,0 +1,29 @@ +import { Hosting } from "../core" + +export enum IdentityType { + USER = "user", // cloud and self hosted users + ACCOUNT = "account", // self hosted accounts + TENANT = "tenant", // cloud and self hosted tenants +} + +export interface Identity { + id: string + tenantId: string +} + +export interface UserIdentity extends Identity { + hosting: Hosting + type: IdentityType + authType: string +} + +export interface BudibaseIdentity extends UserIdentity { + builder?: boolean + admin?: boolean +} + +export interface AccountIdentity extends UserIdentity { + verified: boolean + profession: string | undefined + companySize: string | undefined +} diff --git a/packages/types/src/events/index.ts b/packages/types/src/events/index.ts index e2c4ae8a6d..defd2c7b5b 100644 --- a/packages/types/src/events/index.ts +++ b/packages/types/src/events/index.ts @@ -15,3 +15,4 @@ export * from "./serve" export * from "./table" export * from "./user" export * from "./view" +export * from "./identification" diff --git a/packages/worker/package.json b/packages/worker/package.json index cd7412fa64..9fe6c82325 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -64,7 +64,7 @@ "server-destroy": "^1.0.1" }, "devDependencies": { - "@budibase/types": "^1.0.126-alpha.0", + "@budibase/types": "^1.0.167-alpha.8", "@types/jest": "^26.0.23", "@types/koa": "^2.13.3", "@types/koa-router": "^7.4.2", diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index 247a45c0a3..4555ef05d0 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -71,7 +71,7 @@ export const authenticate = async (ctx: any, next: any) => { "local", async (err: any, user: any, info: any) => { await authInternal(ctx, user, err, info) - events.auth.login("local") + await events.auth.login("local") ctx.status = 200 } )(ctx, next) @@ -112,7 +112,7 @@ export const reset = async (ctx: any) => { user, subject: "{{ company }} platform password reset", }) - events.user.passwordResetRequested(user) + await events.user.passwordResetRequested(user) } } catch (err) { console.log(err) @@ -139,7 +139,7 @@ export const resetUpdate = async (ctx: any) => { } // remove password from the user before sending events delete user.password - events.user.passwordReset(user) + await events.user.passwordReset(user) } catch (err) { ctx.throw(400, "Cannot reset password.") } @@ -212,7 +212,7 @@ export const googleAuth = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: any, info: any) => { await authInternal(ctx, user, err, info) - events.auth.login("google") + await events.auth.login("google") ctx.redirect("/") } )(ctx, next) @@ -256,7 +256,7 @@ export const oidcAuth = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: any, info: any) => { await authInternal(ctx, user, err, info) - events.auth.login("oidc") + await events.auth.login("oidc") ctx.redirect("/") } )(ctx, next) diff --git a/packages/worker/src/api/controllers/global/configs.js b/packages/worker/src/api/controllers/global/configs.js index 8c820d83e8..bfc4ba0f16 100644 --- a/packages/worker/src/api/controllers/global/configs.js +++ b/packages/worker/src/api/controllers/global/configs.js @@ -162,7 +162,7 @@ exports.save = async function (ctx) { try { const response = await db.put(ctx.request.body) for (const fn of eventFns) { - fn() + await fn() } ctx.body = { type, diff --git a/packages/worker/src/api/controllers/global/self.js b/packages/worker/src/api/controllers/global/self.js index ebfc55c55b..28afa69fa0 100644 --- a/packages/worker/src/api/controllers/global/self.js +++ b/packages/worker/src/api/controllers/global/self.js @@ -145,8 +145,8 @@ exports.updateSelf = async ctx => { // remove the old password from the user before sending events delete user.password - events.user.updated(user) + await events.user.updated(user) if (passwordChange) { - events.user.passwordUpdated(user) + await events.user.passwordUpdated(user) } } diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index bcdc7a21bb..acd5bf8c89 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -123,7 +123,7 @@ export const invite = async (ctx: any) => { ctx.body = { message: "Invitation has been sent.", } - events.user.invited(userInfo) + await events.user.invited(userInfo) } export const inviteAccept = async (ctx: any) => { @@ -139,7 +139,7 @@ export const inviteAccept = async (ctx: any) => { email, ...info, }) - events.user.inviteAccepted(user) + await events.user.inviteAccepted(user) return user }) } catch (err: any) { diff --git a/packages/worker/src/sdk/users/events.ts b/packages/worker/src/sdk/users/events.ts index 76108f6853..eace03a3af 100644 --- a/packages/worker/src/sdk/users/events.ts +++ b/packages/worker/src/sdk/users/events.ts @@ -1,19 +1,19 @@ import { events } from "@budibase/backend-core" import { User, UserRoles } from "@budibase/types" -export const handleDeleteEvents = (user: any) => { - events.user.deleted(user) +export const handleDeleteEvents = async (user: any) => { + await events.user.deleted(user) if (isBuilder(user)) { - events.user.permissionBuilderRemoved(user) + await events.user.permissionBuilderRemoved(user) } if (isAdmin(user)) { - events.user.permissionAdminRemoved(user) + await events.user.permissionAdminRemoved(user) } } -const assignAppRoleEvents = ( +const assignAppRoleEvents = async ( user: User, roles: UserRoles, existingRoles: UserRoles @@ -21,12 +21,12 @@ const assignAppRoleEvents = ( for (const [appId, role] of Object.entries(roles)) { // app role in existing is not same as new if (!existingRoles || existingRoles[appId] !== role) { - events.role.assigned(user, role) + await events.role.assigned(user, role) } } } -const unassignAppRoleEvents = ( +const unassignAppRoleEvents = async ( user: User, roles: UserRoles, existingRoles: UserRoles @@ -37,29 +37,29 @@ const unassignAppRoleEvents = ( for (const [appId, role] of Object.entries(existingRoles)) { // app role in new is not same as existing if (!roles || roles[appId] !== role) { - events.role.unassigned(user, role) + await events.role.unassigned(user, role) } } } -const handleAppRoleEvents = (user: any, existingUser: any) => { +const handleAppRoleEvents = async (user: any, existingUser: any) => { const roles = user.roles const existingRoles = existingUser?.roles - assignAppRoleEvents(user, roles, existingRoles) - unassignAppRoleEvents(user, roles, existingRoles) + await assignAppRoleEvents(user, roles, existingRoles) + await unassignAppRoleEvents(user, roles, existingRoles) } -export const handleSaveEvents = (user: any, existingUser: any) => { +export const handleSaveEvents = async (user: any, existingUser: any) => { if (existingUser) { - events.user.updated(user) + await events.user.updated(user) if (isRemovingBuilder(user, existingUser)) { - events.user.permissionBuilderRemoved(user) + await events.user.permissionBuilderRemoved(user) } if (isRemovingAdmin(user, existingUser)) { - events.user.permissionAdminRemoved(user) + await events.user.permissionAdminRemoved(user) } if ( @@ -67,21 +67,21 @@ export const handleSaveEvents = (user: any, existingUser: any) => { user.forceResetPassword && user.password ) { - events.user.passwordForceReset(user) + await events.user.passwordForceReset(user) } } else { - events.user.created(user) + await events.user.created(user) } if (isAddingBuilder(user, existingUser)) { - events.user.permissionBuilderAssigned(user) + await events.user.permissionBuilderAssigned(user) } if (isAddingAdmin(user, existingUser)) { - events.user.permissionAdminAssigned(user) + await events.user.permissionAdminAssigned(user) } - handleAppRoleEvents(user, existingUser) + await handleAppRoleEvents(user, existingUser) } const isBuilder = (user: any) => user.builder && user.builder.global diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index b514392350..0d29dfd190 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -129,7 +129,7 @@ export const save = async ( } user._rev = response.rev - eventHelpers.handleSaveEvents(user, dbUser) + await eventHelpers.handleSaveEvents(user, dbUser) await tenancy.tryAddTenant(tenantId, _id, email) await cache.user.invalidateUser(response.id) @@ -169,7 +169,7 @@ export const destroy = async (id: string, currentUser: any) => { await deprovisioning.removeUserFromInfoDB(dbUser) await db.remove(dbUser._id, dbUser._rev) - eventHelpers.handleDeleteEvents(dbUser) + await eventHelpers.handleDeleteEvents(dbUser) await quotas.removeUser(dbUser) await cache.user.invalidateUser(dbUser._id) await sessions.invalidateSessions(dbUser._id)