diff --git a/packages/backend-core/src/events/processors/AnalyticsProcessor.ts b/packages/backend-core/src/events/processors/AnalyticsProcessor.ts index 30928abc8d..bed06ecb6c 100644 --- a/packages/backend-core/src/events/processors/AnalyticsProcessor.ts +++ b/packages/backend-core/src/events/processors/AnalyticsProcessor.ts @@ -7,7 +7,10 @@ import PosthogProcessor from "./PosthogProcessor" /** * Events that are always captured. */ -const EVENT_WHITELIST = [Event.VERSION_UPGRADED, Event.VERSION_DOWNGRADED] +const EVENT_WHITELIST = [ + Event.INSTALLATION_VERSION_UPGRADED, + Event.INSTALLATION_VERSION_DOWNGRADED, +] const IDENTITY_WHITELIST = [IdentityType.INSTALLATION, IdentityType.TENANT] export default class AnalyticsProcessor implements EventProcessor { diff --git a/packages/backend-core/src/events/publishers/index.ts b/packages/backend-core/src/events/publishers/index.ts index 48b2387c5a..65785d4d8b 100644 --- a/packages/backend-core/src/events/publishers/index.ts +++ b/packages/backend-core/src/events/publishers/index.ts @@ -15,5 +15,5 @@ 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" +export * as installation from "./installation" export * as backfill from "./backfill" diff --git a/packages/backend-core/src/events/publishers/version.ts b/packages/backend-core/src/events/publishers/installation.ts similarity index 53% rename from packages/backend-core/src/events/publishers/version.ts rename to packages/backend-core/src/events/publishers/installation.ts index 1c96ed629f..ef27935210 100644 --- a/packages/backend-core/src/events/publishers/version.ts +++ b/packages/backend-core/src/events/publishers/installation.ts @@ -1,11 +1,11 @@ import { publishEvent } from "../events" import { Event, VersionCheckedEvent, VersionChangeEvent } from "@budibase/types" -export async function checked(version: string) { +export async function versionChecked(version: string) { const properties: VersionCheckedEvent = { currentVersion: version, } - await publishEvent(Event.VERSION_CHECKED, properties) + await publishEvent(Event.INSTALLATION_VERSION_CHECKED, properties) } export async function upgraded(from: string, to: string) { @@ -14,7 +14,7 @@ export async function upgraded(from: string, to: string) { to, } - await publishEvent(Event.VERSION_UPGRADED, properties) + await publishEvent(Event.INSTALLATION_VERSION_UPGRADED, properties) } export async function downgraded(from: string, to: string) { @@ -22,5 +22,10 @@ export async function downgraded(from: string, to: string) { from, to, } - await publishEvent(Event.VERSION_DOWNGRADED, properties) + await publishEvent(Event.INSTALLATION_VERSION_DOWNGRADED, properties) +} + +export async function firstStartup() { + const properties = {} + await publishEvent(Event.INSTALLATION_FIRST_STARTUP, properties) } diff --git a/packages/backend-core/src/installation.ts b/packages/backend-core/src/installation.ts index e95698b336..da9b6c5b76 100644 --- a/packages/backend-core/src/installation.ts +++ b/packages/backend-core/src/installation.ts @@ -84,9 +84,9 @@ export const checkInstallVersion = async (): Promise => { }, async () => { if (isUpgrade) { - await events.version.upgraded(currentVersion, newVersion) + await events.installation.upgraded(currentVersion, newVersion) } else if (isDowngrade) { - await events.version.downgraded(currentVersion, newVersion) + await events.installation.downgraded(currentVersion, newVersion) } } ) diff --git a/packages/backend-core/tests/utilities/mocks/events.js b/packages/backend-core/tests/utilities/mocks/events.js index d2f8f363a1..a4055cc5ea 100644 --- a/packages/backend-core/tests/utilities/mocks/events.js +++ b/packages/backend-core/tests/utilities/mocks/events.js @@ -55,7 +55,7 @@ jest.spyOn(events.org, "logoUpdated") jest.spyOn(events.org, "platformURLUpdated") jest.spyOn(events.org, "analyticsOptOut") -jest.spyOn(events.version, "checked") +jest.spyOn(events.installation, "versionChecked") jest.spyOn(events.query, "created") jest.spyOn(events.query, "updated") diff --git a/packages/server/src/api/controllers/dev.js b/packages/server/src/api/controllers/dev.js index 8e4c597e38..3c5835ac21 100644 --- a/packages/server/src/api/controllers/dev.js +++ b/packages/server/src/api/controllers/dev.js @@ -131,5 +131,5 @@ exports.getBudibaseVersion = async ctx => { ctx.body = { version, } - await events.version.checked(version) + await events.installation.versionChecked(version) } diff --git a/packages/server/src/api/routes/tests/dev.spec.js b/packages/server/src/api/routes/tests/dev.spec.js index 8dee3fd418..db6bad11f4 100644 --- a/packages/server/src/api/routes/tests/dev.spec.js +++ b/packages/server/src/api/routes/tests/dev.spec.js @@ -33,8 +33,8 @@ describe("/dev", () => { .expect(200) expect(res.body.version).toBe(version) - expect(events.version.checked).toBeCalledTimes(1) - expect(events.version.checked).toBeCalledWith(version) + expect(events.installation.versionChecked).toBeCalledTimes(1) + expect(events.installation.versionChecked).toBeCalledWith(version) }) }) }) \ No newline at end of file diff --git a/packages/server/src/migrations/functions/backfill/global.ts b/packages/server/src/migrations/functions/backfill/global.ts index cac38b8066..d61e89fcc9 100644 --- a/packages/server/src/migrations/functions/backfill/global.ts +++ b/packages/server/src/migrations/functions/backfill/global.ts @@ -14,6 +14,7 @@ import { App, TenantBackfillSucceededEvent, Event, + User, } from "@budibase/types" import env from "../../../environment" import { DEFAULT_TIMESTAMP } from "." @@ -94,8 +95,22 @@ export const run = async (db: any) => { const totals: any = {} const errors: any = [] + let allUsers: User[] = [] try { - const installTimestamp = await getInstallTimestamp(db) + allUsers = await users.getUsers(db) + } catch (e: any) { + handleError(e, errors) + } + + if (!allUsers || allUsers.length === 0) { + // first time startup - we don't need to backfill anything + // tenant will be identified when admin user is created + await events.installation.firstStartup() + return + } + + try { + const installTimestamp = await getInstallTimestamp(db, allUsers) if (installTimestamp) { timestamp = installTimestamp } @@ -175,20 +190,25 @@ export const isComplete = async (): Promise => { } export const getInstallTimestamp = async ( - globalDb: any + globalDb: any, + allUsers?: User[] ): Promise => { - const allUsers = await users.getUsers(globalDb) + if (!allUsers) { + allUsers = await users.getUsers(globalDb) + } // get the oldest 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 (allUsers) { + 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] + if (timestamps.length) { + return timestamps[0] + } } } diff --git a/packages/server/src/migrations/index.ts b/packages/server/src/migrations/index.ts index ebba4f420d..494740d1d9 100644 --- a/packages/server/src/migrations/index.ts +++ b/packages/server/src/migrations/index.ts @@ -104,7 +104,6 @@ export const migrate = async (options?: MigrationOptions) => { const migrateWithLock = async (options?: MigrationOptions) => { // get a new lock client - const redlock = await redis.clients.getMigrationsRedlock() // lock for 15 minutes const ttl = 1000 * 60 * 15 diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 64c234417a..5dc1707fa7 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -39,10 +39,11 @@ export enum Event { ORG_LOGO_UPDATED = "org:info:logo:updated", ORG_PLATFORM_URL_UPDATED = "org:platformurl:updated", - // VERSIONS - VERSION_CHECKED = "version:checked", - VERSION_UPGRADED = "version:upgraded", - VERSION_DOWNGRADED = "version:downgraded", + // INSTALLATION + INSTALLATION_VERSION_CHECKED = "installation:version:checked", + INSTALLATION_VERSION_UPGRADED = "installation:version:upgraded", + INSTALLATION_VERSION_DOWNGRADED = "installation:version:downgraded", + INSTALLATION_FIRST_STARTUP = "installation:firstStartup", // ORG / ANALYTICS ANALYTICS_OPT_OUT = "analytics:opt:out",