Installation identities, upgrade / downgrade events, filling in more event properties

This commit is contained in:
Rory Powell 2022-05-26 23:57:14 +01:00
parent cbc3e72757
commit 398a4e7034
35 changed files with 463 additions and 90 deletions

View File

@ -31,6 +31,7 @@ exports.StaticDatabases = {
name: "global-info", name: "global-info",
docs: { docs: {
tenants: "tenants", tenants: "tenants",
install: "install",
}, },
}, },
} }

View File

@ -14,15 +14,21 @@ import {
SettingsConfig, SettingsConfig,
CloudAccount, CloudAccount,
UserIdentity, UserIdentity,
InstallationIdentity,
Installation,
isInstallation,
} from "@budibase/types" } from "@budibase/types"
import { analyticsProcessor } from "./processors" import { processors } from "./processors"
import * as dbUtils from "../db/utils" import * as dbUtils from "../db/utils"
import { Configs } from "../constants" import { Configs } from "../constants"
import * as hashing from "../hashing" import * as hashing from "../hashing"
const pkg = require("../../package.json")
export const getCurrentIdentity = async (): Promise<Identity> => { export const getCurrentIdentity = async (): Promise<Identity> => {
const user: SessionUser | undefined = context.getUser() const user: SessionUser | undefined = context.getUser()
let tenantId = context.getTenantId()
const tenantId = await getGlobalTenantId(context.getTenantId())
let id: string let id: string
let type: IdentityType let type: IdentityType
@ -30,12 +36,14 @@ export const getCurrentIdentity = async (): Promise<Identity> => {
id = user._id id = user._id
type = IdentityType.USER type = IdentityType.USER
} else { } else {
const global = await getGlobalIdentifiers(tenantId) id = tenantId
id = global.id
tenantId = global.tenantId
type = IdentityType.TENANT type = IdentityType.TENANT
} }
if (user && isInstallation(user)) {
type = IdentityType.INSTALLATION
}
return { return {
id, id,
tenantId, tenantId,
@ -43,36 +51,29 @@ export const getCurrentIdentity = async (): Promise<Identity> => {
} }
} }
const getGlobalId = async (): Promise<string> => { const getGlobalId = async (tenantId: string): Promise<string> => {
const db = context.getGlobalDB() const db = context.getGlobalDB()
const config: SettingsConfig = await dbUtils.getScopedFullConfig(db, { const config: SettingsConfig = await dbUtils.getScopedFullConfig(db, {
type: Configs.SETTINGS, type: Configs.SETTINGS,
}) })
let globalId: string
if (config.config.globalId) { if (config.config.globalId) {
return config.config.globalId return config.config.globalId
} else { } else {
const globalId = `global_${hashing.newid()}` globalId = `${hashing.newid()}_${tenantId}`
config.config.globalId = globalId config.config.globalId = globalId
await db.put(config) await db.put(config)
return globalId return globalId
} }
} }
const getGlobalIdentifiers = async ( const getGlobalTenantId = async (tenantId: string): Promise<string> => {
tenantId: string
): Promise<{ id: string; tenantId: string }> => {
if (env.SELF_HOSTED) { if (env.SELF_HOSTED) {
const globalId = await getGlobalId() return getGlobalId(tenantId)
return {
id: globalId,
tenantId: `${globalId}-${tenantId}`,
}
} else { } else {
// tenant id's in the cloud are already unique // tenant id's in the cloud are already unique
return { return tenantId
id: tenantId,
tenantId: tenantId,
}
} }
} }
@ -80,13 +81,34 @@ const getHostingFromEnv = () => {
return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
} }
export const identifyInstallation = async (
install: Installation,
timestamp: string | number
) => {
const id = install.installId
// the default tenant id, so we can match installations to other events
const tenantId = await getGlobalTenantId(context.getTenantId())
const version: string = pkg.version as string
const type = IdentityType.INSTALLATION
const hosting = getHostingFromEnv()
const identity: InstallationIdentity = {
id,
tenantId,
type,
version,
hosting,
}
await identify(identity, timestamp)
}
export const identifyTenant = async ( export const identifyTenant = async (
tenantId: string, tenantId: string,
account: CloudAccount | undefined, account: CloudAccount | undefined,
timestamp?: string | number timestamp?: string | number
) => { ) => {
const global = await getGlobalIdentifiers(tenantId) const globalTenantId = await getGlobalTenantId(tenantId)
const id = global.id const id = globalTenantId
const hosting = getHostingFromEnv() const hosting = getHostingFromEnv()
const type = IdentityType.TENANT const type = IdentityType.TENANT
const profession = account?.profession const profession = account?.profession
@ -94,7 +116,7 @@ export const identifyTenant = async (
const identity: TenantIdentity = { const identity: TenantIdentity = {
id, id,
tenantId: global.tenantId, tenantId: globalTenantId,
hosting, hosting,
type, type,
profession, profession,
@ -116,7 +138,8 @@ export const identifyUser = async (
let admin = user.admin?.global let admin = user.admin?.global
let providerType = user.providerType let providerType = user.providerType
const accountHolder = account?.budibaseUserId === user._id const accountHolder = account?.budibaseUserId === user._id
const verified = account ? account.verified : false const verified =
account && account?.budibaseUserId === user._id ? account.verified : false
const profession = account?.profession const profession = account?.profession
const companySize = account?.size const companySize = account?.size
@ -170,6 +193,9 @@ export const identifyAccount = async (account: Account) => {
await identify(identity) await identify(identity)
} }
const identify = async (identity: Identity, timestamp?: string | number) => { export const identify = async (
await analyticsProcessor.identify(identity, timestamp) identity: Identity,
timestamp?: string | number
) => {
await processors.identify(identity, timestamp)
} }

View File

@ -22,6 +22,21 @@ export default class LoggingProcessor implements EventProcessor {
) )
} }
async identify(identity: Identity, timestamp?: string | number) {
if (env.SELF_HOSTED && !env.isDev()) {
return
}
let timestampString = ""
if (timestamp) {
timestampString = `[timestamp=${new Date(timestamp).toISOString()}]`
}
console.log(
`[audit] [${JSON.stringify(identity)}] ${timestampString} identified`
)
}
shutdown(): void { shutdown(): void {
// no-op // no-op
} }

View File

@ -20,6 +20,15 @@ export default class Processor implements EventProcessor {
} }
} }
async identify(
identity: Identity,
timestamp?: string | number
): Promise<void> {
for (const eventProcessor of this.processors) {
await eventProcessor.identify(identity, timestamp)
}
}
shutdown() { shutdown() {
for (const eventProcessor of this.processors) { for (const eventProcessor of this.processors) {
eventProcessor.shutdown() eventProcessor.shutdown()

View File

@ -12,5 +12,6 @@ export interface EventProcessor {
properties: any, properties: any,
timestamp?: string | number timestamp?: string | number
): Promise<void> ): Promise<void>
identify(identity: Identity, timestamp?: string | number): Promise<void>
shutdown(): void shutdown(): void
} }

View File

@ -10,16 +10,22 @@ import {
SSOType, SSOType,
SSOUpdatedEvent, SSOUpdatedEvent,
} from "@budibase/types" } from "@budibase/types"
import { identification } from ".."
export async function login(source: LoginSource) { export async function login(source: LoginSource) {
const identity = await identification.getCurrentIdentity()
const properties: LoginEvent = { const properties: LoginEvent = {
userId: identity.id,
source, source,
} }
await publishEvent(Event.AUTH_LOGIN, properties) await publishEvent(Event.AUTH_LOGIN, properties)
} }
export async function logout() { export async function logout() {
const properties: LogoutEvent = {} const identity = await identification.getCurrentIdentity()
const properties: LogoutEvent = {
userId: identity.id,
}
await publishEvent(Event.AUTH_LOGOUT, properties) await publishEvent(Event.AUTH_LOGOUT, properties)
} }

View File

@ -3,7 +3,6 @@ import {
Automation, Automation,
Event, Event,
AutomationStep, AutomationStep,
AutomationTrigger,
AutomationCreatedEvent, AutomationCreatedEvent,
AutomationDeletedEvent, AutomationDeletedEvent,
AutomationTestedEvent, AutomationTestedEvent,
@ -13,17 +12,42 @@ import {
} from "@budibase/types" } from "@budibase/types"
export async function created(automation: Automation, timestamp?: string) { export async function created(automation: Automation, timestamp?: string) {
const properties: AutomationCreatedEvent = {} const properties: AutomationCreatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_CREATED, properties, timestamp) await publishEvent(Event.AUTOMATION_CREATED, properties, timestamp)
} }
export async function triggerUpdated(automation: Automation) {
const properties: AutomationTriggerUpdatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties)
}
export async function deleted(automation: Automation) { export async function deleted(automation: Automation) {
const properties: AutomationDeletedEvent = {} const properties: AutomationDeletedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_DELETED, properties) await publishEvent(Event.AUTOMATION_DELETED, properties)
} }
export async function tested(automation: Automation) { export async function tested(automation: Automation) {
const properties: AutomationTestedEvent = {} const properties: AutomationTestedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
}
await publishEvent(Event.AUTOMATION_TESTED, properties) await publishEvent(Event.AUTOMATION_TESTED, properties)
} }
@ -32,7 +56,14 @@ export async function stepCreated(
step: AutomationStep, step: AutomationStep,
timestamp?: string timestamp?: string
) { ) {
const properties: AutomationStepCreatedEvent = {} const properties: AutomationStepCreatedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
stepId: step.id,
stepType: step.stepId,
}
await publishEvent(Event.AUTOMATION_STEP_CREATED, properties, timestamp) await publishEvent(Event.AUTOMATION_STEP_CREATED, properties, timestamp)
} }
@ -40,14 +71,13 @@ export async function stepDeleted(
automation: Automation, automation: Automation,
step: AutomationStep step: AutomationStep
) { ) {
const properties: AutomationStepDeletedEvent = {} const properties: AutomationStepDeletedEvent = {
appId: automation.appId,
automationId: automation._id as string,
triggerId: automation.definition?.trigger?.id,
triggerType: automation.definition?.trigger?.stepId,
stepId: step.id,
stepType: step.stepId,
}
await publishEvent(Event.AUTOMATION_STEP_DELETED, properties) await publishEvent(Event.AUTOMATION_STEP_DELETED, properties)
} }
export async function triggerUpdated(
automation: Automation,
trigger: AutomationTrigger
) {
const properties: AutomationTriggerUpdatedEvent = {}
await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties)
}

View File

@ -8,16 +8,25 @@ import {
} from "@budibase/types" } from "@budibase/types"
export async function created(datasource: Datasource, timestamp?: string) { export async function created(datasource: Datasource, timestamp?: string) {
const properties: DatasourceCreatedEvent = {} const properties: DatasourceCreatedEvent = {
datasourceId: datasource._id as string,
source: datasource.source,
}
await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp) await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
} }
export async function updated(datasource: Datasource) { export async function updated(datasource: Datasource) {
const properties: DatasourceUpdatedEvent = {} const properties: DatasourceUpdatedEvent = {
datasourceId: datasource._id as string,
source: datasource.source,
}
await publishEvent(Event.DATASOURCE_UPDATED, properties) await publishEvent(Event.DATASOURCE_UPDATED, properties)
} }
export async function deleted(datasource: Datasource) { export async function deleted(datasource: Datasource) {
const properties: DatasourceDeletedEvent = {} const properties: DatasourceDeletedEvent = {
datasourceId: datasource._id as string,
source: datasource.source,
}
await publishEvent(Event.DATASOURCE_DELETED, properties) await publishEvent(Event.DATASOURCE_DELETED, properties)
} }

View File

@ -15,3 +15,4 @@ export * as table from "./table"
export * as serve from "./serve" export * as serve from "./serve"
export * as user from "./user" export * as user from "./user"
export * as view from "./view" export * as view from "./view"
export * as version from "./version"

View File

@ -7,11 +7,15 @@ import {
} from "@budibase/types" } from "@budibase/types"
export async function created(layout: Layout, timestamp?: string) { export async function created(layout: Layout, timestamp?: string) {
const properties: LayoutCreatedEvent = {} const properties: LayoutCreatedEvent = {
layoutId: layout._id as string,
}
await publishEvent(Event.LAYOUT_CREATED, properties, timestamp) await publishEvent(Event.LAYOUT_CREATED, properties, timestamp)
} }
export async function deleted(layout: Layout) { export async function deleted(layout: Layout) {
const properties: LayoutDeletedEvent = {} const properties: LayoutDeletedEvent = {
layoutId: layout._id as string,
}
await publishEvent(Event.LAYOUT_DELETED, properties) await publishEvent(Event.LAYOUT_DELETED, properties)
} }

View File

@ -1,5 +1,5 @@
import { publishEvent } from "../events" import { publishEvent } from "../events"
import { Event, VersionCheckedEvent } from "@budibase/types" import { Event } from "@budibase/types"
export async function nameUpdated(timestamp?: string | number) { export async function nameUpdated(timestamp?: string | number) {
const properties = {} const properties = {}
@ -16,14 +16,8 @@ export async function platformURLUpdated(timestamp?: string | number) {
await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties, timestamp) await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties, timestamp)
} }
export async function versionChecked(version: number) {
const properties: VersionCheckedEvent = {
version,
}
await publishEvent(Event.UPDATE_VERSION_CHECKED, properties)
}
// TODO // TODO
export async function analyticsOptOut() { export async function analyticsOptOut() {
const properties = {} const properties = {}
await publishEvent(Event.ANALYTICS_OPT_OUT, properties) await publishEvent(Event.ANALYTICS_OPT_OUT, properties)

View File

@ -0,0 +1,26 @@
import { publishEvent } from "../events"
import { Event, VersionCheckedEvent, VersionChangeEvent } from "@budibase/types"
export async function checked(version: string) {
const properties: VersionCheckedEvent = {
currentVersion: version,
}
await publishEvent(Event.VERSION_CHECKED, properties)
}
export async function upgraded(from: string, to: string) {
const properties: VersionChangeEvent = {
from,
to,
}
await publishEvent(Event.VERSION_UPGRADED, properties)
}
export async function downgraded(from: string, to: string) {
const properties: VersionChangeEvent = {
from,
to,
}
await publishEvent(Event.VERSION_DOWNGRADED, properties)
}

View File

@ -1,6 +1,6 @@
const { DEFAULT_TENANT_ID } = require("../constants") const { DEFAULT_TENANT_ID } = require("../constants")
const { doWithDB } = require("../db") const { doWithDB } = require("../db")
const { DocumentTypes } = require("../db/constants") const { DocumentTypes, StaticDatabases } = require("../db/constants")
const { getAllApps } = require("../db/utils") const { getAllApps } = require("../db/utils")
const environment = require("../environment") const environment = require("../environment")
const { const {
@ -11,8 +11,9 @@ const {
} = require("../tenancy") } = require("../tenancy")
exports.MIGRATION_TYPES = { exports.MIGRATION_TYPES = {
GLOBAL: "global", // run once, recorded in global db, global db is provided as an argument GLOBAL: "global", // run once per tenant, recorded in global db, global db is provided as an argument
APP: "app", // run per app, recorded in each app db, app db is provided as an argument APP: "app", // run per app, recorded in each app db, app db is provided as an argument
INSTALLATION: "installation", // run once, recorded in global info db, global info db is provided as an argument
} }
exports.getMigrationsDoc = async db => { exports.getMigrationsDoc = async db => {
@ -22,14 +23,19 @@ exports.getMigrationsDoc = async db => {
} catch (err) { } catch (err) {
if (err.status && err.status === 404) { if (err.status && err.status === 404) {
return { _id: DocumentTypes.MIGRATIONS } return { _id: DocumentTypes.MIGRATIONS }
} else {
console.error(err)
throw err
} }
console.error(err)
} }
} }
exports.runMigration = async (migration, options = {}) => { exports.runMigration = async (migration, options = {}) => {
const tenantId = getTenantId()
const migrationType = migration.type const migrationType = migration.type
let tenantId
if (migrationType !== exports.MIGRATION_TYPES.INSTALLATION) {
tenantId = getTenantId()
}
const migrationName = migration.name const migrationName = migration.name
const silent = migration.silent const silent = migration.silent
@ -46,10 +52,10 @@ exports.runMigration = async (migration, options = {}) => {
} else if (migrationType === exports.MIGRATION_TYPES.APP) { } else if (migrationType === exports.MIGRATION_TYPES.APP) {
const apps = await getAllApps(migration.opts) const apps = await getAllApps(migration.opts)
dbNames = apps.map(app => app.appId) dbNames = apps.map(app => app.appId)
} else if (migrationType === exports.MIGRATION_TYPES.INSTALLATION) {
dbNames = [StaticDatabases.PLATFORM_INFO.name]
} else { } else {
throw new Error( throw new Error(`Unrecognised migration type [${migrationType}]`)
`[Tenant: ${tenantId}] Unrecognised migration type [${migrationType}]`
)
} }
const length = dbNames.length const length = dbNames.length

View File

@ -129,6 +129,7 @@
"pouchdb-find": "^7.2.2", "pouchdb-find": "^7.2.2",
"pouchdb-replication-stream": "1.2.9", "pouchdb-replication-stream": "1.2.9",
"redis": "4", "redis": "4",
"semver": "^7.0.0",
"server-destroy": "1.0.1", "server-destroy": "1.0.1",
"svelte": "^3.38.2", "svelte": "^3.38.2",
"swagger-parser": "^10.0.3", "swagger-parser": "^10.0.3",
@ -159,6 +160,7 @@
"@types/node": "^15.12.4", "@types/node": "^15.12.4",
"@types/oracledb": "^5.2.1", "@types/oracledb": "^5.2.1",
"@types/redis": "^4.0.11", "@types/redis": "^4.0.11",
"@types/semver": "^7.0.0",
"@typescript-eslint/parser": "5.12.0", "@typescript-eslint/parser": "5.12.0",
"apidoc": "^0.50.2", "apidoc": "^0.50.2",
"babel-jest": "^27.0.2", "babel-jest": "^27.0.2",

View File

@ -131,5 +131,5 @@ exports.getBudibaseVersion = async ctx => {
ctx.body = { ctx.body = {
version, version,
} }
await events.org.versionChecked(version) await events.version.versionChecked(version)
} }

View File

@ -17,6 +17,7 @@ const bullboard = require("./automations/bullboard")
import redis from "./utilities/redis" import redis from "./utilities/redis"
import * as migrations from "./migrations" import * as migrations from "./migrations"
import { events } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import * as installation from "./installation"
const app = new Koa() const app = new Koa()
@ -108,3 +109,6 @@ if (!env.HTTP_MIGRATIONS && !env.isTest()) {
shutdown() shutdown()
}) })
} }
// check for version updates
installation.checkInstallVersion()

View File

@ -0,0 +1,92 @@
import {
db as dbUtils,
events,
utils,
context,
tenancy,
} from "@budibase/backend-core"
import { Installation } from "@budibase/types"
import semver from "semver"
const pkg = require("../package.json")
export const getInstall = async (): Promise<Installation> => {
return dbUtils.doWithDB(
dbUtils.StaticDatabases.PLATFORM_INFO.name,
async (platformDb: any) => {
let install: Installation
try {
install = await platformDb.get(
dbUtils.StaticDatabases.PLATFORM_INFO.docs.install
)
} catch (e: any) {
if (e.status === 404) {
install = {
_id: dbUtils.StaticDatabases.PLATFORM_INFO.docs.install,
installId: utils.newid(),
version: pkg.version,
}
const resp = await platformDb.put(install)
install._rev = resp.rev
} else {
throw e
}
}
return install
},
{}
)
}
const updateVersion = async (version: string): Promise<boolean> => {
try {
await dbUtils.doWithDB(
dbUtils.StaticDatabases.PLATFORM_INFO.name,
async (platformDb: any) => {
const install = await getInstall()
install.version = version
await platformDb.put(install)
},
{}
)
} catch (e: any) {
if (e.status === 409) {
// do nothing - version has already been updated
// likely in clustered environment
return false
}
throw e
}
return true
}
export const checkInstallVersion = async (): Promise<void> => {
const install = await getInstall()
const currentVersion = install.version
const newVersion = pkg.version
if (currentVersion !== newVersion) {
const isUpgrade = semver.gt(newVersion, currentVersion)
const isDowngrade = semver.lt(newVersion, currentVersion)
const success = await updateVersion(newVersion)
if (success) {
await context.doInUserContext(
{
_id: install.installId,
isInstall: true,
tenantId: tenancy.DEFAULT_TENANT_ID,
},
async () => {
if (isUpgrade) {
await events.version.upgraded(currentVersion, newVersion)
} else if (isDowngrade) {
await events.version.downgraded(currentVersion, newVersion)
}
}
)
}
}
}

View File

@ -2,8 +2,9 @@ import * as users from "./global/users"
import * as rows from "./global/rows" import * as rows from "./global/rows"
import * as configs from "./global/configs" import * as configs from "./global/configs"
import { tenancy, events, migrations, accounts } from "@budibase/backend-core" import { tenancy, events, migrations, accounts } from "@budibase/backend-core"
import { CloudAccount } from "@budibase/types" import { CloudAccount, Installation } from "@budibase/types"
import env from "../../../environment" import env from "../../../environment"
import * as installation from "../../../installation"
/** /**
* Date: * Date:
@ -39,10 +40,12 @@ export const isComplete = async (): Promise<boolean> => {
return !!migrationsDoc.event_global_backfill return !!migrationsDoc.event_global_backfill
} }
const getInstallTimestamp = async (db: any): Promise<number | undefined> => { export const getInstallTimestamp = async (
const allUsers = await users.getUsers(db) globalDb: any
): Promise<number | undefined> => {
const allUsers = await users.getUsers(globalDb)
// get the olders user timestamp // get the oldest user timestamp
const timestamps = allUsers const timestamps = allUsers
.map(user => user.createdAt) .map(user => user.createdAt)
.filter(timestamp => !!timestamp) .filter(timestamp => !!timestamp)

View File

@ -1,2 +1,3 @@
export * as app from "./app" export * as app from "./app"
export * as global from "./global" export * as global from "./global"
export * as installation from "./installation"

View File

@ -0,0 +1,22 @@
import { events, tenancy } from "@budibase/backend-core"
import { Installation } from "@budibase/types"
import * as installation from "../../../installation"
import * as global from "./global"
/**
* Date:
* May 2022
*
* Description:
* Backfill installation events.
*/
export const run = async () => {
// need to use the default tenant to try to get the installation time
await tenancy.doInTenant(tenancy.DEFAULT_TENANT_ID, async () => {
const db = tenancy.getGlobalDB()
const installTimestamp = (await global.getInstallTimestamp(db)) as number
const install: Installation = await installation.getInstall()
await events.identification.identifyInstallation(install, installTimestamp)
})
}

View File

@ -73,6 +73,12 @@ export const MIGRATIONS: Migration[] = [
fn: backfill.global.run, fn: backfill.global.run,
silent: !!env.SELF_HOSTED, // reduce noisy logging silent: !!env.SELF_HOSTED, // reduce noisy logging
}, },
{
type: migrations.MIGRATION_TYPES.INSTALLATION,
name: "event_installation_backfill",
fn: backfill.installation.run,
silent: !!env.SELF_HOSTED, // reduce noisy logging
},
] ]
export const migrate = async (options?: MigrationOptions) => { export const migrate = async (options?: MigrationOptions) => {

View File

@ -2754,6 +2754,11 @@
"@types/tough-cookie" "*" "@types/tough-cookie" "*"
form-data "^2.5.0" form-data "^2.5.0"
"@types/semver@^7.0.0":
version "7.3.9"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc"
integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==
"@types/serve-static@*": "@types/serve-static@*":
version "1.13.10" version "1.13.10"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9"
@ -11645,6 +11650,13 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.0.0:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
seq-queue@^0.0.5: seq-queue@^0.0.5:
version "0.0.5" version "0.0.5"
resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e"

View File

@ -33,4 +33,17 @@ export const isUserSession = (
return !user.account || user.account?.hosting === Hosting.CLOUD return !user.account || user.account?.hosting === Hosting.CLOUD
} }
export type SessionUser = AccountUserSession | BudibaseUserSession // not technically a session, but used to identify the installation
export interface InstallationSession {
_id: string
isInstallation: boolean
}
export const isInstallation = (user: any): user is InstallationSession => {
return !!user.isInstallation
}
export type SessionUser =
| AccountUserSession
| BudibaseUserSession
| InstallationSession

View File

@ -5,8 +5,15 @@ export interface Automation extends Document {
steps: AutomationStep[] steps: AutomationStep[]
trigger: AutomationTrigger trigger: AutomationTrigger
} }
appId: string
} }
export interface AutomationStep {} export interface AutomationStep {
id: string
stepId: string
}
export interface AutomationTrigger {} export interface AutomationTrigger {
id: string
stepId: string
}

View File

@ -1,3 +1,5 @@
import { Document } from "../document" import { Document } from "../document"
export interface Datasource extends Document {} export interface Datasource extends Document {
source: string
}

View File

@ -1 +1,9 @@
import { Document } from "../document"
export interface GlobalInfo {} export interface GlobalInfo {}
export interface Installation extends Document {
_id: string
installId: string
version: string
}

View File

@ -2,15 +2,26 @@ export type LoginSource = "local" | "google" | "oidc"
export type SSOType = "oidc" | "google" export type SSOType = "oidc" | "google"
export interface LoginEvent { export interface LoginEvent {
userId: string
source: LoginSource source: LoginSource
} }
export interface LogoutEvent {} export interface LogoutEvent {
userId: string
}
export interface SSOCreatedEvent {} export interface SSOCreatedEvent {
type: SSOType
}
export interface SSOUpdatedEvent {} export interface SSOUpdatedEvent {
type: SSOType
}
export interface SSOActivatedEvent {} export interface SSOActivatedEvent {
type: SSOType
}
export interface SSODeactivatedEvent {} export interface SSODeactivatedEvent {
type: SSOType
}

View File

@ -1,11 +1,45 @@
export interface AutomationCreatedEvent {} export interface AutomationCreatedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
}
export interface AutomationDeletedEvent {} export interface AutomationTriggerUpdatedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
}
export interface AutomationTestedEvent {} export interface AutomationDeletedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
}
export interface AutomationStepCreatedEvent {} export interface AutomationTestedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
}
export interface AutomationStepDeletedEvent {} export interface AutomationStepCreatedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
stepId: string
stepType: string
}
export interface AutomationTriggerUpdatedEvent {} export interface AutomationStepDeletedEvent {
appId: string
automationId: string
triggerId: string
triggerType: string
stepId: string
stepType: string
}

View File

@ -1,5 +1,14 @@
export interface DatasourceCreatedEvent {} export interface DatasourceCreatedEvent {
datasourceId: string
source: string
}
export interface DatasourceUpdatedEvent {} export interface DatasourceUpdatedEvent {
datasourceId: string
source: string
}
export interface DatasourceDeletedEvent {} export interface DatasourceDeletedEvent {
datasourceId: string
source: string
}

View File

@ -38,7 +38,9 @@ export enum Event {
ORG_PLATFORM_URL_UPDATED = "org:platformurl:updated", ORG_PLATFORM_URL_UPDATED = "org:platformurl:updated",
// ORG / UPDATE // ORG / UPDATE
UPDATE_VERSION_CHECKED = "version:checked", VERSION_CHECKED = "version:checked",
VERSION_UPGRADED = "version:upgraded",
VERSION_DOWNGRADED = "version:downgraded",
// ORG / ANALYTICS // ORG / ANALYTICS
ANALYTICS_OPT_OUT = "analytics:opt:out", ANALYTICS_OPT_OUT = "analytics:opt:out",

View File

@ -1,8 +1,9 @@
import { Hosting } from "../core" import { Hosting } from "../core"
export enum IdentityType { export enum IdentityType {
USER = "user", // cloud and self hosted users USER = "user",
TENANT = "tenant", // cloud and self hosted tenants TENANT = "tenant",
INSTALLATION = "installation",
} }
export interface Identity { export interface Identity {
@ -11,6 +12,11 @@ export interface Identity {
type: IdentityType type: IdentityType
} }
export interface InstallationIdentity extends Identity {
version: string
hosting: Hosting
}
export interface TenantIdentity extends Identity { export interface TenantIdentity extends Identity {
hosting: Hosting hosting: Hosting
profession?: string profession?: string

View File

@ -6,7 +6,7 @@ export * from "./datasource"
export * from "./event" export * from "./event"
export * from "./layout" export * from "./layout"
export * from "./license" export * from "./license"
export * from "./org" export * from "./version"
export * from "./query" export * from "./query"
export * from "./role" export * from "./role"
export * from "./rows" export * from "./rows"

View File

@ -1,3 +1,7 @@
export interface LayoutCreatedEvent {} export interface LayoutCreatedEvent {
layoutId: string
}
export interface LayoutDeletedEvent {} export interface LayoutDeletedEvent {
layoutId: string
}

View File

@ -1 +0,0 @@
export interface VersionCheckedEvent {}

View File

@ -0,0 +1,8 @@
export interface VersionCheckedEvent {
currentVersion: string
}
export interface VersionChangeEvent {
from: string
to: string
}