Installation identities, upgrade / downgrade events, filling in more event properties
This commit is contained in:
parent
cbc3e72757
commit
398a4e7034
|
@ -31,6 +31,7 @@ exports.StaticDatabases = {
|
|||
name: "global-info",
|
||||
docs: {
|
||||
tenants: "tenants",
|
||||
install: "install",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -14,15 +14,21 @@ import {
|
|||
SettingsConfig,
|
||||
CloudAccount,
|
||||
UserIdentity,
|
||||
InstallationIdentity,
|
||||
Installation,
|
||||
isInstallation,
|
||||
} from "@budibase/types"
|
||||
import { analyticsProcessor } from "./processors"
|
||||
import { processors } from "./processors"
|
||||
import * as dbUtils from "../db/utils"
|
||||
import { Configs } from "../constants"
|
||||
import * as hashing from "../hashing"
|
||||
|
||||
const pkg = require("../../package.json")
|
||||
|
||||
export const getCurrentIdentity = async (): Promise<Identity> => {
|
||||
const user: SessionUser | undefined = context.getUser()
|
||||
let tenantId = context.getTenantId()
|
||||
|
||||
const tenantId = await getGlobalTenantId(context.getTenantId())
|
||||
let id: string
|
||||
let type: IdentityType
|
||||
|
||||
|
@ -30,12 +36,14 @@ export const getCurrentIdentity = async (): Promise<Identity> => {
|
|||
id = user._id
|
||||
type = IdentityType.USER
|
||||
} else {
|
||||
const global = await getGlobalIdentifiers(tenantId)
|
||||
id = global.id
|
||||
tenantId = global.tenantId
|
||||
id = tenantId
|
||||
type = IdentityType.TENANT
|
||||
}
|
||||
|
||||
if (user && isInstallation(user)) {
|
||||
type = IdentityType.INSTALLATION
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
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 config: SettingsConfig = await dbUtils.getScopedFullConfig(db, {
|
||||
type: Configs.SETTINGS,
|
||||
})
|
||||
|
||||
let globalId: string
|
||||
if (config.config.globalId) {
|
||||
return config.config.globalId
|
||||
} else {
|
||||
const globalId = `global_${hashing.newid()}`
|
||||
globalId = `${hashing.newid()}_${tenantId}`
|
||||
config.config.globalId = globalId
|
||||
await db.put(config)
|
||||
return globalId
|
||||
}
|
||||
}
|
||||
|
||||
const getGlobalIdentifiers = async (
|
||||
tenantId: string
|
||||
): Promise<{ id: string; tenantId: string }> => {
|
||||
const getGlobalTenantId = async (tenantId: string): Promise<string> => {
|
||||
if (env.SELF_HOSTED) {
|
||||
const globalId = await getGlobalId()
|
||||
return {
|
||||
id: globalId,
|
||||
tenantId: `${globalId}-${tenantId}`,
|
||||
}
|
||||
return getGlobalId(tenantId)
|
||||
} else {
|
||||
// tenant id's in the cloud are already unique
|
||||
return {
|
||||
id: tenantId,
|
||||
tenantId: tenantId,
|
||||
}
|
||||
return tenantId
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,13 +81,34 @@ const getHostingFromEnv = () => {
|
|||
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 (
|
||||
tenantId: string,
|
||||
account: CloudAccount | undefined,
|
||||
timestamp?: string | number
|
||||
) => {
|
||||
const global = await getGlobalIdentifiers(tenantId)
|
||||
const id = global.id
|
||||
const globalTenantId = await getGlobalTenantId(tenantId)
|
||||
const id = globalTenantId
|
||||
const hosting = getHostingFromEnv()
|
||||
const type = IdentityType.TENANT
|
||||
const profession = account?.profession
|
||||
|
@ -94,7 +116,7 @@ export const identifyTenant = async (
|
|||
|
||||
const identity: TenantIdentity = {
|
||||
id,
|
||||
tenantId: global.tenantId,
|
||||
tenantId: globalTenantId,
|
||||
hosting,
|
||||
type,
|
||||
profession,
|
||||
|
@ -116,7 +138,8 @@ export const identifyUser = async (
|
|||
let admin = user.admin?.global
|
||||
let providerType = user.providerType
|
||||
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 companySize = account?.size
|
||||
|
||||
|
@ -170,6 +193,9 @@ export const identifyAccount = async (account: Account) => {
|
|||
await identify(identity)
|
||||
}
|
||||
|
||||
const identify = async (identity: Identity, timestamp?: string | number) => {
|
||||
await analyticsProcessor.identify(identity, timestamp)
|
||||
export const identify = async (
|
||||
identity: Identity,
|
||||
timestamp?: string | number
|
||||
) => {
|
||||
await processors.identify(identity, timestamp)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
// no-op
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
for (const eventProcessor of this.processors) {
|
||||
eventProcessor.shutdown()
|
||||
|
|
|
@ -12,5 +12,6 @@ export interface EventProcessor {
|
|||
properties: any,
|
||||
timestamp?: string | number
|
||||
): Promise<void>
|
||||
identify(identity: Identity, timestamp?: string | number): Promise<void>
|
||||
shutdown(): void
|
||||
}
|
||||
|
|
|
@ -10,16 +10,22 @@ import {
|
|||
SSOType,
|
||||
SSOUpdatedEvent,
|
||||
} from "@budibase/types"
|
||||
import { identification } from ".."
|
||||
|
||||
export async function login(source: LoginSource) {
|
||||
const identity = await identification.getCurrentIdentity()
|
||||
const properties: LoginEvent = {
|
||||
userId: identity.id,
|
||||
source,
|
||||
}
|
||||
await publishEvent(Event.AUTH_LOGIN, properties)
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
const properties: LogoutEvent = {}
|
||||
const identity = await identification.getCurrentIdentity()
|
||||
const properties: LogoutEvent = {
|
||||
userId: identity.id,
|
||||
}
|
||||
await publishEvent(Event.AUTH_LOGOUT, properties)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
Automation,
|
||||
Event,
|
||||
AutomationStep,
|
||||
AutomationTrigger,
|
||||
AutomationCreatedEvent,
|
||||
AutomationDeletedEvent,
|
||||
AutomationTestedEvent,
|
||||
|
@ -13,17 +12,42 @@ import {
|
|||
} from "@budibase/types"
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -32,7 +56,14 @@ export async function stepCreated(
|
|||
step: AutomationStep,
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -40,14 +71,13 @@ export async function stepDeleted(
|
|||
automation: Automation,
|
||||
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)
|
||||
}
|
||||
|
||||
export async function triggerUpdated(
|
||||
automation: Automation,
|
||||
trigger: AutomationTrigger
|
||||
) {
|
||||
const properties: AutomationTriggerUpdatedEvent = {}
|
||||
await publishEvent(Event.AUTOMATION_TRIGGER_UPDATED, properties)
|
||||
}
|
||||
|
|
|
@ -8,16 +8,25 @@ import {
|
|||
} from "@budibase/types"
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -15,3 +15,4 @@ export * as table from "./table"
|
|||
export * as serve from "./serve"
|
||||
export * as user from "./user"
|
||||
export * as view from "./view"
|
||||
export * as version from "./version"
|
||||
|
|
|
@ -7,11 +7,15 @@ import {
|
|||
} from "@budibase/types"
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
export async function deleted(layout: Layout) {
|
||||
const properties: LayoutDeletedEvent = {}
|
||||
const properties: LayoutDeletedEvent = {
|
||||
layoutId: layout._id as string,
|
||||
}
|
||||
await publishEvent(Event.LAYOUT_DELETED, properties)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { publishEvent } from "../events"
|
||||
import { Event, VersionCheckedEvent } from "@budibase/types"
|
||||
import { Event } from "@budibase/types"
|
||||
|
||||
export async function nameUpdated(timestamp?: string | number) {
|
||||
const properties = {}
|
||||
|
@ -16,14 +16,8 @@ export async function platformURLUpdated(timestamp?: string | number) {
|
|||
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
|
||||
|
||||
export async function analyticsOptOut() {
|
||||
const properties = {}
|
||||
await publishEvent(Event.ANALYTICS_OPT_OUT, properties)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
const { DEFAULT_TENANT_ID } = require("../constants")
|
||||
const { doWithDB } = require("../db")
|
||||
const { DocumentTypes } = require("../db/constants")
|
||||
const { DocumentTypes, StaticDatabases } = require("../db/constants")
|
||||
const { getAllApps } = require("../db/utils")
|
||||
const environment = require("../environment")
|
||||
const {
|
||||
|
@ -11,8 +11,9 @@ const {
|
|||
} = require("../tenancy")
|
||||
|
||||
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
|
||||
INSTALLATION: "installation", // run once, recorded in global info db, global info db is provided as an argument
|
||||
}
|
||||
|
||||
exports.getMigrationsDoc = async db => {
|
||||
|
@ -22,14 +23,19 @@ exports.getMigrationsDoc = async db => {
|
|||
} catch (err) {
|
||||
if (err.status && err.status === 404) {
|
||||
return { _id: DocumentTypes.MIGRATIONS }
|
||||
} else {
|
||||
console.error(err)
|
||||
throw err
|
||||
}
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
exports.runMigration = async (migration, options = {}) => {
|
||||
const tenantId = getTenantId()
|
||||
const migrationType = migration.type
|
||||
let tenantId
|
||||
if (migrationType !== exports.MIGRATION_TYPES.INSTALLATION) {
|
||||
tenantId = getTenantId()
|
||||
}
|
||||
const migrationName = migration.name
|
||||
const silent = migration.silent
|
||||
|
||||
|
@ -46,10 +52,10 @@ exports.runMigration = async (migration, options = {}) => {
|
|||
} else if (migrationType === exports.MIGRATION_TYPES.APP) {
|
||||
const apps = await getAllApps(migration.opts)
|
||||
dbNames = apps.map(app => app.appId)
|
||||
} else if (migrationType === exports.MIGRATION_TYPES.INSTALLATION) {
|
||||
dbNames = [StaticDatabases.PLATFORM_INFO.name]
|
||||
} else {
|
||||
throw new Error(
|
||||
`[Tenant: ${tenantId}] Unrecognised migration type [${migrationType}]`
|
||||
)
|
||||
throw new Error(`Unrecognised migration type [${migrationType}]`)
|
||||
}
|
||||
|
||||
const length = dbNames.length
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
"pouchdb-find": "^7.2.2",
|
||||
"pouchdb-replication-stream": "1.2.9",
|
||||
"redis": "4",
|
||||
"semver": "^7.0.0",
|
||||
"server-destroy": "1.0.1",
|
||||
"svelte": "^3.38.2",
|
||||
"swagger-parser": "^10.0.3",
|
||||
|
@ -159,6 +160,7 @@
|
|||
"@types/node": "^15.12.4",
|
||||
"@types/oracledb": "^5.2.1",
|
||||
"@types/redis": "^4.0.11",
|
||||
"@types/semver": "^7.0.0",
|
||||
"@typescript-eslint/parser": "5.12.0",
|
||||
"apidoc": "^0.50.2",
|
||||
"babel-jest": "^27.0.2",
|
||||
|
|
|
@ -131,5 +131,5 @@ exports.getBudibaseVersion = async ctx => {
|
|||
ctx.body = {
|
||||
version,
|
||||
}
|
||||
await events.org.versionChecked(version)
|
||||
await events.version.versionChecked(version)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ const bullboard = require("./automations/bullboard")
|
|||
import redis from "./utilities/redis"
|
||||
import * as migrations from "./migrations"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import * as installation from "./installation"
|
||||
|
||||
const app = new Koa()
|
||||
|
||||
|
@ -108,3 +109,6 @@ if (!env.HTTP_MIGRATIONS && !env.isTest()) {
|
|||
shutdown()
|
||||
})
|
||||
}
|
||||
|
||||
// check for version updates
|
||||
installation.checkInstallVersion()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,9 @@ import * as users from "./global/users"
|
|||
import * as rows from "./global/rows"
|
||||
import * as configs from "./global/configs"
|
||||
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 * as installation from "../../../installation"
|
||||
|
||||
/**
|
||||
* Date:
|
||||
|
@ -39,10 +40,12 @@ export const isComplete = async (): Promise<boolean> => {
|
|||
return !!migrationsDoc.event_global_backfill
|
||||
}
|
||||
|
||||
const getInstallTimestamp = async (db: any): Promise<number | undefined> => {
|
||||
const allUsers = await users.getUsers(db)
|
||||
export const getInstallTimestamp = async (
|
||||
globalDb: any
|
||||
): Promise<number | undefined> => {
|
||||
const allUsers = await users.getUsers(globalDb)
|
||||
|
||||
// get the olders user timestamp
|
||||
// get the oldest user timestamp
|
||||
const timestamps = allUsers
|
||||
.map(user => user.createdAt)
|
||||
.filter(timestamp => !!timestamp)
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * as app from "./app"
|
||||
export * as global from "./global"
|
||||
export * as installation from "./installation"
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -73,6 +73,12 @@ export const MIGRATIONS: Migration[] = [
|
|||
fn: backfill.global.run,
|
||||
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) => {
|
||||
|
|
|
@ -2754,6 +2754,11 @@
|
|||
"@types/tough-cookie" "*"
|
||||
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@*":
|
||||
version "1.13.10"
|
||||
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"
|
||||
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:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e"
|
||||
|
|
|
@ -33,4 +33,17 @@ export const isUserSession = (
|
|||
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
|
||||
|
|
|
@ -5,8 +5,15 @@ export interface Automation extends Document {
|
|||
steps: AutomationStep[]
|
||||
trigger: AutomationTrigger
|
||||
}
|
||||
appId: string
|
||||
}
|
||||
|
||||
export interface AutomationStep {}
|
||||
export interface AutomationStep {
|
||||
id: string
|
||||
stepId: string
|
||||
}
|
||||
|
||||
export interface AutomationTrigger {}
|
||||
export interface AutomationTrigger {
|
||||
id: string
|
||||
stepId: string
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { Document } from "../document"
|
||||
|
||||
export interface Datasource extends Document {}
|
||||
export interface Datasource extends Document {
|
||||
source: string
|
||||
}
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
import { Document } from "../document"
|
||||
|
||||
export interface GlobalInfo {}
|
||||
|
||||
export interface Installation extends Document {
|
||||
_id: string
|
||||
installId: string
|
||||
version: string
|
||||
}
|
||||
|
|
|
@ -2,15 +2,26 @@ export type LoginSource = "local" | "google" | "oidc"
|
|||
export type SSOType = "oidc" | "google"
|
||||
|
||||
export interface LoginEvent {
|
||||
userId: string
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -38,7 +38,9 @@ export enum Event {
|
|||
ORG_PLATFORM_URL_UPDATED = "org:platformurl:updated",
|
||||
|
||||
// ORG / UPDATE
|
||||
UPDATE_VERSION_CHECKED = "version:checked",
|
||||
VERSION_CHECKED = "version:checked",
|
||||
VERSION_UPGRADED = "version:upgraded",
|
||||
VERSION_DOWNGRADED = "version:downgraded",
|
||||
|
||||
// ORG / ANALYTICS
|
||||
ANALYTICS_OPT_OUT = "analytics:opt:out",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { Hosting } from "../core"
|
||||
|
||||
export enum IdentityType {
|
||||
USER = "user", // cloud and self hosted users
|
||||
TENANT = "tenant", // cloud and self hosted tenants
|
||||
USER = "user",
|
||||
TENANT = "tenant",
|
||||
INSTALLATION = "installation",
|
||||
}
|
||||
|
||||
export interface Identity {
|
||||
|
@ -11,6 +12,11 @@ export interface Identity {
|
|||
type: IdentityType
|
||||
}
|
||||
|
||||
export interface InstallationIdentity extends Identity {
|
||||
version: string
|
||||
hosting: Hosting
|
||||
}
|
||||
|
||||
export interface TenantIdentity extends Identity {
|
||||
hosting: Hosting
|
||||
profession?: string
|
||||
|
|
|
@ -6,7 +6,7 @@ export * from "./datasource"
|
|||
export * from "./event"
|
||||
export * from "./layout"
|
||||
export * from "./license"
|
||||
export * from "./org"
|
||||
export * from "./version"
|
||||
export * from "./query"
|
||||
export * from "./role"
|
||||
export * from "./rows"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export interface LayoutCreatedEvent {}
|
||||
export interface LayoutCreatedEvent {
|
||||
layoutId: string
|
||||
}
|
||||
|
||||
export interface LayoutDeletedEvent {}
|
||||
export interface LayoutDeletedEvent {
|
||||
layoutId: string
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export interface VersionCheckedEvent {}
|
|
@ -0,0 +1,8 @@
|
|||
export interface VersionCheckedEvent {
|
||||
currentVersion: string
|
||||
}
|
||||
|
||||
export interface VersionChangeEvent {
|
||||
from: string
|
||||
to: string
|
||||
}
|
Loading…
Reference in New Issue