Historical timestamps

This commit is contained in:
Rory Powell 2022-05-25 21:32:08 +01:00
parent 1eed4da35f
commit b986b689d6
36 changed files with 226 additions and 178 deletions

View File

@ -79,7 +79,10 @@ const getHostingFromEnv = () => {
return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD return env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
} }
export const identifyTenant = async (tenantId: string) => { export const identifyTenant = async (
tenantId: string,
timestamp?: string | number
) => {
const global = await getGlobalIdentifiers(tenantId) const global = await getGlobalIdentifiers(tenantId)
const identity: TenantIdentity = { const identity: TenantIdentity = {
@ -88,10 +91,10 @@ export const identifyTenant = async (tenantId: string) => {
hosting: getHostingFromEnv(), hosting: getHostingFromEnv(),
type: IdentityType.TENANT, type: IdentityType.TENANT,
} }
await identify(identity) await identify(identity, timestamp)
} }
export const identifyUser = async (user: User) => { export const identifyUser = async (user: User, timestamp?: string | number) => {
const id = user._id as string const id = user._id as string
const tenantId = user.tenantId const tenantId = user.tenantId
const hosting = env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD const hosting = env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
@ -110,7 +113,7 @@ export const identifyUser = async (user: User) => {
providerType, providerType,
} }
await identify(identity) await identify(identity, timestamp)
} }
export const identifyAccount = async (account: Account) => { export const identifyAccount = async (account: Account) => {
@ -141,6 +144,6 @@ export const identifyAccount = async (account: Account) => {
await identify(identity) await identify(identity)
} }
const identify = async (identity: Identity) => { const identify = async (identity: Identity, timestamp?: string | number) => {
await analyticsProcessor.identify(identity) await analyticsProcessor.identify(identity, timestamp)
} }

View File

@ -17,7 +17,7 @@ export default class AnalyticsProcessor implements EventProcessor {
event: Event, event: Event,
identity: Identity, identity: Identity,
properties: any, properties: any,
timestamp?: string timestamp?: string | number
): Promise<void> { ): Promise<void> {
if (!(await analytics.enabled())) { if (!(await analytics.enabled())) {
return return
@ -27,12 +27,12 @@ export default class AnalyticsProcessor implements EventProcessor {
} }
} }
async identify(identity: Identity) { async identify(identity: Identity, timestamp?: string | number) {
if (!(await analytics.enabled())) { if (!(await analytics.enabled())) {
return return
} }
if (this.posthog) { if (this.posthog) {
this.posthog.identify(identity) this.posthog.identify(identity, timestamp)
} }
} }

View File

@ -25,8 +25,12 @@ export default class PosthogProcessor implements EventProcessor {
this.posthog.capture(payload) this.posthog.capture(payload)
} }
async identify(identity: Identity) { async identify(identity: Identity, timestamp?: string | number) {
this.posthog.identify({ distinctId: identity.id, properties: identity }) const payload: any = { distinctId: identity.id, properties: identity }
if (timestamp) {
payload.timestamp = new Date(timestamp)
}
this.posthog.identify(payload)
} }
shutdown() { shutdown() {

View File

@ -15,9 +15,9 @@ import {
AppExportedEvent, AppExportedEvent,
} from "@budibase/types" } from "@budibase/types"
export const created = async (app: App) => { export const created = async (app: App, timestamp?: string | number) => {
const properties: AppCreatedEvent = {} const properties: AppCreatedEvent = {}
await publishEvent(Event.APP_CREATED, properties) await publishEvent(Event.APP_CREATED, properties, timestamp)
} }
export async function updated(app: App) { export async function updated(app: App) {
@ -30,9 +30,9 @@ export async function deleted(app: App) {
await publishEvent(Event.APP_DELETED, properties) await publishEvent(Event.APP_DELETED, properties)
} }
export async function published(app: App) { export async function published(app: App, timestamp?: string | number) {
const properties: AppPublishedEvent = {} const properties: AppPublishedEvent = {}
await publishEvent(Event.APP_PUBLISHED, properties) await publishEvent(Event.APP_PUBLISHED, properties, timestamp)
} }
export async function unpublished(app: App) { export async function unpublished(app: App) {

View File

@ -23,11 +23,11 @@ export async function logout() {
await publishEvent(Event.AUTH_LOGOUT, properties) await publishEvent(Event.AUTH_LOGOUT, properties)
} }
export async function SSOCreated(type: SSOType) { export async function SSOCreated(type: SSOType, timestamp?: string | number) {
const properties: SSOCreatedEvent = { const properties: SSOCreatedEvent = {
type, type,
} }
await publishEvent(Event.AUTH_SSO_CREATED, properties) await publishEvent(Event.AUTH_SSO_CREATED, properties, timestamp)
} }
export async function SSOUpdated(type: SSOType) { export async function SSOUpdated(type: SSOType) {
@ -37,11 +37,11 @@ export async function SSOUpdated(type: SSOType) {
await publishEvent(Event.AUTH_SSO_UPDATED, properties) await publishEvent(Event.AUTH_SSO_UPDATED, properties)
} }
export async function SSOActivated(type: SSOType) { export async function SSOActivated(type: SSOType, timestamp?: string | number) {
const properties: SSOActivatedEvent = { const properties: SSOActivatedEvent = {
type, type,
} }
await publishEvent(Event.AUTH_SSO_ACTIVATED, properties) await publishEvent(Event.AUTH_SSO_ACTIVATED, properties, timestamp)
} }
export async function SSODeactivated(type: SSOType) { export async function SSODeactivated(type: SSOType) {

View File

@ -12,9 +12,9 @@ import {
AutomationTriggerUpdatedEvent, AutomationTriggerUpdatedEvent,
} from "@budibase/types" } from "@budibase/types"
export async function created(automation: Automation) { export async function created(automation: Automation, timestamp?: string) {
const properties: AutomationCreatedEvent = {} const properties: AutomationCreatedEvent = {}
await publishEvent(Event.AUTOMATION_CREATED, properties) await publishEvent(Event.AUTOMATION_CREATED, properties, timestamp)
} }
export async function deleted(automation: Automation) { export async function deleted(automation: Automation) {
@ -29,10 +29,11 @@ export async function tested(automation: Automation) {
export async function stepCreated( export async function stepCreated(
automation: Automation, automation: Automation,
step: AutomationStep step: AutomationStep,
timestamp?: string
) { ) {
const properties: AutomationStepCreatedEvent = {} const properties: AutomationStepCreatedEvent = {}
await publishEvent(Event.AUTOMATION_STEP_CREATED, properties) await publishEvent(Event.AUTOMATION_STEP_CREATED, properties, timestamp)
} }
export async function stepDeleted( export async function stepDeleted(

View File

@ -7,9 +7,9 @@ import {
DatasourceDeletedEvent, DatasourceDeletedEvent,
} from "@budibase/types" } from "@budibase/types"
export async function created(datasource: Datasource) { export async function created(datasource: Datasource, timestamp?: string) {
const properties: DatasourceCreatedEvent = {} const properties: DatasourceCreatedEvent = {}
await publishEvent(Event.DATASOURCE_CREATED, properties) await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
} }
export async function updated(datasource: Datasource) { export async function updated(datasource: Datasource) {

View File

@ -6,9 +6,12 @@ import {
SMTPUpdatedEvent, SMTPUpdatedEvent,
} from "@budibase/types" } from "@budibase/types"
export async function SMTPCreated(config: SMTPConfig) { export async function SMTPCreated(
config: SMTPConfig,
timestamp?: string | number
) {
const properties: SMTPCreatedEvent = {} const properties: SMTPCreatedEvent = {}
await publishEvent(Event.EMAIL_SMTP_CREATED, properties) await publishEvent(Event.EMAIL_SMTP_CREATED, properties, timestamp)
} }
export async function SMTPUpdated(config: SMTPConfig) { export async function SMTPUpdated(config: SMTPConfig) {

View File

@ -6,9 +6,9 @@ import {
LayoutDeletedEvent, LayoutDeletedEvent,
} from "@budibase/types" } from "@budibase/types"
export async function created(layout: Layout) { export async function created(layout: Layout, timestamp?: string) {
const properties: LayoutCreatedEvent = {} const properties: LayoutCreatedEvent = {}
await publishEvent(Event.LAYOUT_CREATED, properties) await publishEvent(Event.LAYOUT_CREATED, properties, timestamp)
} }
export async function deleted(layout: Layout) { export async function deleted(layout: Layout) {

View File

@ -1,19 +1,19 @@
import { publishEvent } from "../events" import { publishEvent } from "../events"
import { Event, VersionCheckedEvent } from "@budibase/types" import { Event, VersionCheckedEvent } from "@budibase/types"
export async function nameUpdated() { export async function nameUpdated(timestamp?: string | number) {
const properties = {} const properties = {}
await publishEvent(Event.ORG_NAME_UPDATED, properties) await publishEvent(Event.ORG_NAME_UPDATED, properties, timestamp)
} }
export async function logoUpdated() { export async function logoUpdated(timestamp?: string | number) {
const properties = {} const properties = {}
await publishEvent(Event.ORG_LOGO_UPDATED, properties) await publishEvent(Event.ORG_LOGO_UPDATED, properties, timestamp)
} }
export async function platformURLUpdated() { export async function platformURLUpdated(timestamp?: string | number) {
const properties = {} const properties = {}
await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties) await publishEvent(Event.ORG_PLATFORM_URL_UPDATED, properties, timestamp)
} }
export async function versionChecked(version: number) { export async function versionChecked(version: number) {

View File

@ -12,9 +12,13 @@ import {
/* eslint-disable */ /* eslint-disable */
export const created = async (datasource: Datasource, query: Query) => { export const created = async (
datasource: Datasource,
query: Query,
timestamp?: string
) => {
const properties: QueryCreatedEvent = {} const properties: QueryCreatedEvent = {}
await publishEvent(Event.QUERY_CREATED, properties) await publishEvent(Event.QUERY_CREATED, properties, timestamp)
} }
export const updated = async (datasource: Datasource, query: Query) => { export const updated = async (datasource: Datasource, query: Query) => {

View File

@ -12,9 +12,9 @@ import {
/* eslint-disable */ /* eslint-disable */
export async function created(role: Role) { export async function created(role: Role, timestamp?: string) {
const properties: RoleCreatedEvent = {} const properties: RoleCreatedEvent = {}
await publishEvent(Event.ROLE_CREATED, properties) await publishEvent(Event.ROLE_CREATED, properties, timestamp)
} }
export async function updated(role: Role) { export async function updated(role: Role) {
@ -27,9 +27,9 @@ export async function deleted(role: Role) {
await publishEvent(Event.ROLE_DELETED, properties) await publishEvent(Event.ROLE_DELETED, properties)
} }
export async function assigned(user: User, role: string) { export async function assigned(user: User, role: string, timestamp?: number) {
const properties: RoleAssignedEvent = {} const properties: RoleAssignedEvent = {}
await publishEvent(Event.ROLE_ASSIGNED, properties) await publishEvent(Event.ROLE_ASSIGNED, properties, timestamp)
} }
export async function unassigned(user: User, role: string) { export async function unassigned(user: User, role: string) {

View File

@ -9,11 +9,11 @@ import {
/* eslint-disable */ /* eslint-disable */
export const created = async (count: number) => { export const created = async (count: number, timestamp?: string) => {
const properties: RowsCreatedEvent = { const properties: RowsCreatedEvent = {
count, count,
} }
await publishEvent(Event.ROWS_CREATED, properties) await publishEvent(Event.ROWS_CREATED, properties, timestamp)
} }
export const imported = async ( export const imported = async (

View File

@ -6,9 +6,9 @@ import {
ScreenDeletedEvent, ScreenDeletedEvent,
} from "@budibase/types" } from "@budibase/types"
export async function created(screen: Screen) { export async function created(screen: Screen, timestamp?: string) {
const properties: ScreenCreatedEvent = {} const properties: ScreenCreatedEvent = {}
await publishEvent(Event.SCREEN_CREATED, properties) await publishEvent(Event.SCREEN_CREATED, properties, timestamp)
} }
export async function deleted(screen: Screen) { export async function deleted(screen: Screen) {

View File

@ -13,9 +13,9 @@ import {
/* eslint-disable */ /* eslint-disable */
export async function created(table: Table) { export async function created(table: Table, timestamp?: string) {
const properties: TableCreatedEvent = {} const properties: TableCreatedEvent = {}
await publishEvent(Event.TABLE_CREATED, properties) await publishEvent(Event.TABLE_CREATED, properties, timestamp)
} }
export async function updated(table: Table) { export async function updated(table: Table) {

View File

@ -17,9 +17,9 @@ import {
/* eslint-disable */ /* eslint-disable */
export async function created(user: User) { export async function created(user: User, timestamp?: number) {
const properties: UserCreatedEvent = {} const properties: UserCreatedEvent = {}
await publishEvent(Event.USER_CREATED, properties) await publishEvent(Event.USER_CREATED, properties, timestamp)
} }
export async function updated(user: User) { export async function updated(user: User) {
@ -34,9 +34,13 @@ export async function deleted(user: User) {
// PERMISSIONS // PERMISSIONS
export async function permissionAdminAssigned(user: User) { export async function permissionAdminAssigned(user: User, timestamp?: number) {
const properties: UserPermissionAssignedEvent = {} const properties: UserPermissionAssignedEvent = {}
await publishEvent(Event.USER_PERMISSION_ADMIN_ASSIGNED, properties) await publishEvent(
Event.USER_PERMISSION_ADMIN_ASSIGNED,
properties,
timestamp
)
} }
export async function permissionAdminRemoved(user: User) { export async function permissionAdminRemoved(user: User) {
@ -44,9 +48,16 @@ export async function permissionAdminRemoved(user: User) {
await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties) await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties)
} }
export async function permissionBuilderAssigned(user: User) { export async function permissionBuilderAssigned(
user: User,
timestamp?: number
) {
const properties: UserPermissionAssignedEvent = {} const properties: UserPermissionAssignedEvent = {}
await publishEvent(Event.USER_PERMISSION_BUILDER_ASSIGNED, properties) await publishEvent(
Event.USER_PERMISSION_BUILDER_ASSIGNED,
properties,
timestamp
)
} }
export async function permissionBuilderRemoved(user: User) { export async function permissionBuilderRemoved(user: User) {

View File

@ -19,9 +19,9 @@ import {
/* eslint-disable */ /* eslint-disable */
export async function created(view: View) { export async function created(view: View, timestamp?: string) {
const properties: ViewCreatedEvent = {} const properties: ViewCreatedEvent = {}
await publishEvent(Event.VIEW_CREATED, properties) await publishEvent(Event.VIEW_CREATED, properties, timestamp)
} }
export async function updated(view: View) { export async function updated(view: View) {
@ -39,9 +39,9 @@ export async function exported(table: Table, format: TableExportFormat) {
await publishEvent(Event.VIEW_EXPORTED, properties) await publishEvent(Event.VIEW_EXPORTED, properties)
} }
export async function filterCreated() { export async function filterCreated(timestamp?: string) {
const properties: ViewFilterCreatedEvent = {} const properties: ViewFilterCreatedEvent = {}
await publishEvent(Event.VIEW_FILTER_CREATED, properties) await publishEvent(Event.VIEW_FILTER_CREATED, properties, timestamp)
} }
export async function filterUpdated() { export async function filterUpdated() {
@ -54,9 +54,12 @@ export async function filterDeleted() {
await publishEvent(Event.VIEW_FILTER_DELETED, properties) await publishEvent(Event.VIEW_FILTER_DELETED, properties)
} }
export async function calculationCreated(calculation: ViewCalculation) { export async function calculationCreated(
calculation: ViewCalculation,
timestamp?: string
) {
const properties: ViewCalculationCreatedEvent = {} const properties: ViewCalculationCreatedEvent = {}
await publishEvent(Event.VIEW_CALCULATION_CREATED, properties) await publishEvent(Event.VIEW_CALCULATION_CREATED, properties, timestamp)
} }
export async function calculationUpdated() { export async function calculationUpdated() {

View File

@ -1,4 +1,3 @@
import * as apps from "./app/apps"
import * as automations from "./app/automations" import * as automations from "./app/automations"
import * as datasources from "./app/datasources" import * as datasources from "./app/datasources"
import * as layouts from "./app/layouts" import * as layouts from "./app/layouts"
@ -7,6 +6,8 @@ import * as roles from "./app/roles"
import * as tables from "./app/tables" import * as tables from "./app/tables"
import * as screens from "./app/screens" import * as screens from "./app/screens"
import * as global from "./global" import * as global from "./global"
import { App } from "@budibase/types"
import { db as dbUtils, events } from "@budibase/backend-core"
/** /**
* Date: * Date:
@ -24,12 +25,21 @@ export const run = async (appDb: any) => {
return return
} }
await apps.backfill(appDb) const app: App = await appDb.get(dbUtils.DocumentTypes.APP_METADATA)
await automations.backfill(appDb) const timestamp = app.createdAt as string
await datasources.backfill(appDb)
await layouts.backfill(appDb) if (dbUtils.isDevAppID(app.appId)) {
await queries.backfill(appDb) await events.app.created(app, timestamp)
await roles.backfill(appDb) await automations.backfill(appDb, timestamp)
await tables.backfill(appDb) await datasources.backfill(appDb, timestamp)
await screens.backfill(appDb) await layouts.backfill(appDb, timestamp)
await queries.backfill(appDb, timestamp)
await roles.backfill(appDb, timestamp)
await tables.backfill(appDb, timestamp)
await screens.backfill(appDb, timestamp)
}
if (dbUtils.isProdAppID(app.appId)) {
await events.app.published(app, timestamp)
}
} }

View File

@ -1,14 +0,0 @@
import { events, db } from "@budibase/backend-core"
import { App } from "@budibase/types"
export const backfill = async (appDb: any) => {
const app: App = await appDb.get(db.DocumentTypes.APP_METADATA)
if (db.isDevAppID(app.appId)) {
await events.app.created(app)
}
if (db.isProdAppID(app.appId)) {
await events.app.published(app)
}
}

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getAutomationParams } from "../../../../db/utils" import { getAutomationParams } from "../../../../db/utils"
import { Automation } from "@budibase/types" import { Automation } from "@budibase/types"
@ -11,16 +11,14 @@ const getAutomations = async (appDb: any): Promise<Automation[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const automations = await getAutomations(appDb)
const automations = await getAutomations(appDb)
for (const automation of automations) { for (const automation of automations) {
await events.automation.created(automation) await events.automation.created(automation, timestamp)
for (const step of automation.definition.steps) { for (const step of automation.definition.steps) {
await events.automation.stepCreated(automation, step) await events.automation.stepCreated(automation, step, timestamp)
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getDatasourceParams } from "../../../../db/utils" import { getDatasourceParams } from "../../../../db/utils"
import { Datasource } from "@budibase/types" import { Datasource } from "@budibase/types"
@ -11,12 +11,10 @@ const getDatasources = async (appDb: any): Promise<Datasource[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const datasources: Datasource[] = await getDatasources(appDb)
const datasources: Datasource[] = await getDatasources(appDb)
for (const datasource of datasources) { for (const datasource of datasources) {
await events.datasource.created(datasource) await events.datasource.created(datasource, timestamp)
}
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getLayoutParams } from "../../../../db/utils" import { getLayoutParams } from "../../../../db/utils"
import { Layout } from "@budibase/types" import { Layout } from "@budibase/types"
@ -11,12 +11,10 @@ const getLayouts = async (appDb: any): Promise<Layout[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const layouts: Layout[] = await getLayouts(appDb)
const layouts: Layout[] = await getLayouts(appDb)
for (const layout of layouts) { for (const layout of layouts) {
await events.layout.created(layout) await events.layout.created(layout, timestamp)
}
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getQueryParams } from "../../../../db/utils" import { getQueryParams } from "../../../../db/utils"
import { Query, Datasource } from "@budibase/types" import { Query, Datasource } from "@budibase/types"
@ -18,16 +18,14 @@ const getDatasource = async (
return appDb.get(datasourceId) return appDb.get(datasourceId)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const queries: Query[] = await getQueries(appDb)
const queries: Query[] = await getQueries(appDb)
for (const query of queries) { for (const query of queries) {
const datasource: Datasource = await getDatasource( const datasource: Datasource = await getDatasource(
appDb, appDb,
query.datasourceId query.datasourceId
) )
await events.query.created(datasource, query) await events.query.created(datasource, query, timestamp)
}
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getRoleParams } from "../../../../db/utils" import { getRoleParams } from "../../../../db/utils"
import { Role } from "@budibase/types" import { Role } from "@budibase/types"
@ -11,12 +11,10 @@ const getRoles = async (appDb: any): Promise<Role[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const roles = await getRoles(appDb)
const roles = await getRoles(appDb)
for (const role of roles) { for (const role of roles) {
await events.role.created(role) await events.role.created(role, timestamp)
}
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getScreenParams } from "../../../../db/utils" import { getScreenParams } from "../../../../db/utils"
import { Screen } from "@budibase/types" import { Screen } from "@budibase/types"
@ -11,12 +11,10 @@ const getScreens = async (appDb: any): Promise<Screen[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const screens = await getScreens(appDb)
const screens = await getScreens(appDb)
for (const screen of screens) { for (const screen of screens) {
await events.screen.created(screen) await events.screen.created(screen, timestamp)
}
} }
} }

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events } from "@budibase/backend-core"
import { getTableParams } from "../../../../db/utils" import { getTableParams } from "../../../../db/utils"
import { Table } from "@budibase/types" import { Table } from "@budibase/types"
@ -11,24 +11,22 @@ const getTables = async (appDb: any): Promise<Table[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (appDb: any) => { export const backfill = async (appDb: any, timestamp: string) => {
if (db.isDevAppID(appDb.name)) { const tables = await getTables(appDb)
const tables = await getTables(appDb)
for (const table of tables) { for (const table of tables) {
await events.table.created(table) await events.table.created(table, timestamp)
if (table.views) { if (table.views) {
for (const view of Object.values(table.views)) { for (const view of Object.values(table.views)) {
await events.view.created(view) await events.view.created(view, timestamp)
if (view.calculation) { if (view.calculation) {
await events.view.calculationCreated(view.calculation) await events.view.calculationCreated(view.calculation, timestamp)
} }
if (view.filters?.length) { if (view.filters?.length) {
await events.view.filterCreated() await events.view.filterCreated(timestamp)
}
} }
} }
} }

View File

@ -13,11 +13,14 @@ import { tenancy, events, migrations } from "@budibase/backend-core"
export const run = async (db: any) => { export const run = async (db: any) => {
const tenantId = tenancy.getTenantId() const tenantId = tenancy.getTenantId()
await events.identification.identifyTenant(tenantId) const installTimestamp = (await getInstallTimestamp(db)) as number
await events.identification.identifyTenant(tenantId, installTimestamp)
await configs.backfill(db, installTimestamp)
// users and rows provide their own timestamp
await users.backfill(db) await users.backfill(db)
await rows.backfill() await rows.backfill()
await configs.backfill(db)
} }
export const isComplete = async (): Promise<boolean> => { export const isComplete = async (): Promise<boolean> => {
@ -25,3 +28,20 @@ export const isComplete = async (): Promise<boolean> => {
const migrationsDoc = await migrations.getMigrationsDoc(globalDb) const migrationsDoc = await migrations.getMigrationsDoc(globalDb)
return !!migrationsDoc.event_global_backfill return !!migrationsDoc.event_global_backfill
} }
const getInstallTimestamp = async (db: any): Promise<number | undefined> => {
const allUsers = await users.getUsers(db)
// get the olders user timestamp
const timestamps = allUsers
.map(user => user.createdAt)
.filter(timestamp => !!timestamp)
.sort(
(a, b) =>
new Date(a as number).getTime() - new Date(b as number).getTime()
)
if (timestamps.length) {
return timestamps[0]
}
}

View File

@ -1,4 +1,4 @@
import { events, db } from "@budibase/backend-core" import { events, db as dbUtils } from "@budibase/backend-core"
import { import {
Config, Config,
isSMTPConfig, isSMTPConfig,
@ -10,7 +10,7 @@ import env from "./../../../../environment"
const getConfigs = async (globalDb: any): Promise<Config[]> => { const getConfigs = async (globalDb: any): Promise<Config[]> => {
const response = await globalDb.allDocs( const response = await globalDb.allDocs(
db.getConfigParams( dbUtils.getConfigParams(
{}, {},
{ {
include_docs: true, include_docs: true,
@ -20,34 +20,37 @@ const getConfigs = async (globalDb: any): Promise<Config[]> => {
return response.rows.map((row: any) => row.doc) return response.rows.map((row: any) => row.doc)
} }
export const backfill = async (globalDb: any) => { export const backfill = async (
globalDb: any,
timestamp: string | number | undefined
) => {
const configs = await getConfigs(globalDb) const configs = await getConfigs(globalDb)
for (const config of configs) { for (const config of configs) {
if (isSMTPConfig(config)) { if (isSMTPConfig(config)) {
await events.email.SMTPCreated(config) await events.email.SMTPCreated(config, timestamp)
} }
if (isGoogleConfig(config)) { if (isGoogleConfig(config)) {
await events.auth.SSOCreated("google") await events.auth.SSOCreated("google", timestamp)
if (config.config.activated) { if (config.config.activated) {
await events.auth.SSOActivated("google") await events.auth.SSOActivated("google", timestamp)
} }
} }
if (isOIDCConfig(config)) { if (isOIDCConfig(config)) {
await events.auth.SSOCreated("oidc") await events.auth.SSOCreated("oidc", timestamp)
if (config.config.configs[0].activated) { if (config.config.configs[0].activated) {
await events.auth.SSOActivated("oidc") await events.auth.SSOActivated("oidc", timestamp)
} }
} }
if (isSettingsConfig(config)) { if (isSettingsConfig(config)) {
const company = config.config.company const company = config.config.company
if (company && company !== "Budibase") { if (company && company !== "Budibase") {
await events.org.nameUpdated() await events.org.nameUpdated(timestamp)
} }
const logoUrl = config.config.logoUrl const logoUrl = config.config.logoUrl
if (logoUrl) { if (logoUrl) {
await events.org.logoUpdated() await events.org.logoUpdated(timestamp)
} }
const platformUrl = config.config.platformUrl const platformUrl = config.config.platformUrl
@ -56,7 +59,7 @@ export const backfill = async (globalDb: any) => {
platformUrl !== "http://localhost:10000" && platformUrl !== "http://localhost:10000" &&
env.SELF_HOSTED env.SELF_HOSTED
) { ) {
await events.org.platformURLUpdated() await events.org.platformURLUpdated(timestamp)
} }
} }
} }

View File

@ -1,16 +1,28 @@
import { events, db } from "@budibase/backend-core" import { events, db as dbUtils } from "@budibase/backend-core"
import { Row } from "@budibase/types" import { Row, App } from "@budibase/types"
import { getUniqueRows } from "../../../../utilities/usageQuota/rows" import { getUniqueRows } from "../../../../utilities/usageQuota/rows"
// Rows is a special circumstance where we get rows across all apps // Rows is a special circumstance where we get rows across all apps
// therefore migration is performed at the global level // therefore migration is performed at the global level
const getOldestCreatedAt = (allApps: App[]): string | undefined => {
const timestamps = allApps
.filter(app => !!app.createdAt)
.map(app => app.createdAt as string)
.sort((a, b) => new Date(a).getTime() - new Date(b).getTime())
if (timestamps.length) {
return timestamps[0]
}
}
export const backfill = async () => { export const backfill = async () => {
const allApps = await db.getAllApps({ all: true }) const allApps: App[] = await dbUtils.getAllApps({ dev: true })
const timestamp = getOldestCreatedAt(allApps)
const appIds = allApps ? allApps.map((app: { appId: any }) => app.appId) : [] const appIds = allApps ? allApps.map((app: { appId: any }) => app.appId) : []
const rows: Row[] = await getUniqueRows(appIds) const rows: Row[] = await getUniqueRows(appIds)
const rowCount = rows ? rows.length : 0 const rowCount = rows ? rows.length : 0
if (rowCount) { if (rowCount) {
await events.rows.created(rowCount) await events.rows.created(rowCount, timestamp)
} }
} }

View File

@ -1,12 +1,12 @@
import { events, db } from "@budibase/backend-core" import { events, db as dbUtils } from "@budibase/backend-core"
import { User } from "@budibase/types" import { User } from "@budibase/types"
// manually define user doc params - normally server doesn't read users from the db // manually define user doc params - normally server doesn't read users from the db
const getUserParams = (props: any) => { const getUserParams = (props: any) => {
return db.getDocParams(db.DocumentTypes.USER, null, props) return dbUtils.getDocParams(dbUtils.DocumentTypes.USER, null, props)
} }
const getUsers = async (globalDb: any): Promise<User[]> => { export const getUsers = async (globalDb: any): Promise<User[]> => {
const response = await globalDb.allDocs( const response = await globalDb.allDocs(
getUserParams({ getUserParams({
include_docs: true, include_docs: true,
@ -19,20 +19,21 @@ export const backfill = async (globalDb: any) => {
const users = await getUsers(globalDb) const users = await getUsers(globalDb)
for (const user of users) { for (const user of users) {
await events.identification.identifyUser(user) const timestamp = user.createdAt as number
await events.user.created(user) await events.identification.identifyUser(user, timestamp)
await events.user.created(user, timestamp)
if (user.admin?.global) { if (user.admin?.global) {
await events.user.permissionAdminAssigned(user) await events.user.permissionAdminAssigned(user, timestamp)
} }
if (user.builder?.global) { if (user.builder?.global) {
await events.user.permissionBuilderAssigned(user) await events.user.permissionBuilderAssigned(user, timestamp)
} }
if (user.roles) { if (user.roles) {
for (const [appId, role] of Object.entries(user.roles)) { for (const [appId, role] of Object.entries(user.roles)) {
await events.role.assigned(user, role) await events.role.assigned(user, role, timestamp)
} }
} }
} }

View File

@ -2,7 +2,8 @@
// Used for building with tsc // Used for building with tsc
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"references": [ "references": [
{ "path": "../backend-core/tsconfig.build.json" } { "path": "../backend-core/tsconfig.build.json" },
{ "path": "../types" }
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",

View File

@ -16,9 +16,6 @@
"./src/**/*", "./src/**/*",
"./src/module.d.ts" "./src/module.d.ts"
], ],
"references": [
{ "path": "../backend-core/tsconfig.build.json" }
],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"**/*.json", "**/*.json",

View File

@ -1,6 +1,6 @@
export interface Document { export interface Document {
_id?: string _id?: string
_rev?: string _rev?: string
createdAt?: string createdAt?: string | number
updatedAt?: string updatedAt?: string
} }

View File

@ -1,6 +1,8 @@
import { Document } from "../document" import { Document } from "../document"
export interface User extends Document { export interface User extends Document {
tenantId: string
email: string
roles: UserRoles roles: UserRoles
builder?: { builder?: {
global: boolean global: boolean
@ -9,10 +11,9 @@ export interface User extends Document {
global: boolean global: boolean
} }
providerType?: string providerType?: string
tenantId: string
email: string
password?: string password?: string
status?: string status?: string
createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now()
} }
export interface UserRoles { export interface UserRoles {

View File

@ -10,6 +10,7 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"incremental": true, "incremental": true,
"types": [ "node"], "types": [ "node"],
"composite": true
}, },
"include": [ "include": [
"**/*.ts", "**/*.ts",

View File

@ -13,7 +13,8 @@
"types": [ "node", "jest"], "types": [ "node", "jest"],
}, },
"references": [ "references": [
{ "path": "../backend-core/tsconfig.build.json" } { "path": "../backend-core/tsconfig.build.json" },
{ "path": "../types" }
], ],
"include": [ "include": [
"./src/**/*" "./src/**/*"