diff --git a/packages/backend-core/src/events/publishers/datasource.ts b/packages/backend-core/src/events/publishers/datasource.ts index 3cd68033fc..d3ea7402f9 100644 --- a/packages/backend-core/src/events/publishers/datasource.ts +++ b/packages/backend-core/src/events/publishers/datasource.ts @@ -5,8 +5,15 @@ import { DatasourceCreatedEvent, DatasourceUpdatedEvent, DatasourceDeletedEvent, + SourceName, } from "@budibase/types" +function isCustom(datasource: Datasource) { + const sources = Object.values(SourceName) + // if not in the base source list, then it must be custom + return !sources.includes(datasource.source) +} + export async function created( datasource: Datasource, timestamp?: string | number @@ -14,6 +21,7 @@ export async function created( const properties: DatasourceCreatedEvent = { datasourceId: datasource._id as string, source: datasource.source, + custom: isCustom(datasource), } await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp) } @@ -22,6 +30,7 @@ export async function updated(datasource: Datasource) { const properties: DatasourceUpdatedEvent = { datasourceId: datasource._id as string, source: datasource.source, + custom: isCustom(datasource), } await publishEvent(Event.DATASOURCE_UPDATED, properties) } @@ -30,6 +39,7 @@ export async function deleted(datasource: Datasource) { const properties: DatasourceDeletedEvent = { datasourceId: datasource._id as string, source: datasource.source, + custom: isCustom(datasource), } await publishEvent(Event.DATASOURCE_DELETED, properties) } diff --git a/packages/backend-core/src/events/publishers/index.ts b/packages/backend-core/src/events/publishers/index.ts index 57fd0bf8e2..6fe42c4bda 100644 --- a/packages/backend-core/src/events/publishers/index.ts +++ b/packages/backend-core/src/events/publishers/index.ts @@ -18,3 +18,4 @@ export * as view from "./view" export * as installation from "./installation" export * as backfill from "./backfill" export * as group from "./group" +export * as plugin from "./plugin" diff --git a/packages/backend-core/src/events/publishers/plugin.ts b/packages/backend-core/src/events/publishers/plugin.ts new file mode 100644 index 0000000000..4e4d87cf56 --- /dev/null +++ b/packages/backend-core/src/events/publishers/plugin.ts @@ -0,0 +1,41 @@ +import { publishEvent } from "../events" +import { + Event, + Plugin, + PluginDeletedEvent, + PluginImportedEvent, + PluginInitEvent, +} from "@budibase/types" + +export async function init(plugin: Plugin) { + const properties: PluginInitEvent = { + type: plugin.schema.type, + name: plugin.name, + description: plugin.description, + version: plugin.version, + } + await publishEvent(Event.PLUGIN_INIT, properties) +} + +export async function imported(plugin: Plugin) { + const properties: PluginImportedEvent = { + pluginId: plugin._id as string, + type: plugin.schema.type, + source: plugin.source, + name: plugin.name, + description: plugin.description, + version: plugin.version, + } + await publishEvent(Event.PLUGIN_IMPORTED, properties) +} + +export async function deleted(plugin: Plugin) { + const properties: PluginDeletedEvent = { + pluginId: plugin._id as string, + type: plugin.schema.type, + name: plugin.name, + description: plugin.description, + version: plugin.version, + } + await publishEvent(Event.PLUGIN_DELETED, properties) +} diff --git a/packages/cli/src/constants.js b/packages/cli/src/constants.js index 8fe6c8602d..aa49523d4e 100644 --- a/packages/cli/src/constants.js +++ b/packages/cli/src/constants.js @@ -1,3 +1,5 @@ +const { Event } = require("@budibase/types") + exports.CommandWords = { BACKUPS: "backups", HOSTING: "hosting", @@ -15,6 +17,7 @@ exports.AnalyticsEvents = { OptOut: "analytics:opt:out", OptIn: "analytics:opt:in", SelfHostInit: "hosting:init", + PluginInit: Event.PLUGIN_INIT, } exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS" diff --git a/packages/cli/src/events.js b/packages/cli/src/events.js new file mode 100644 index 0000000000..63d4fca1ea --- /dev/null +++ b/packages/cli/src/events.js @@ -0,0 +1,11 @@ +const AnalyticsClient = require("./analytics/Client") + +const client = new AnalyticsClient() + +exports.captureEvent = (event, properties) => { + client.capture({ + distinctId: "cli", + event, + properties, + }) +} diff --git a/packages/cli/src/hosting/index.js b/packages/cli/src/hosting/index.js index 2ebcee43a5..ae62c45992 100644 --- a/packages/cli/src/hosting/index.js +++ b/packages/cli/src/hosting/index.js @@ -13,7 +13,7 @@ const fs = require("fs") const compose = require("docker-compose") const makeEnv = require("./makeEnv") const axios = require("axios") -const AnalyticsClient = require("../analytics/Client") +const { captureEvent } = require("../events") const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"] const ERROR_FILE = "docker-error.log" @@ -22,8 +22,6 @@ const FILE_URLS = [ ] const DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data" -const client = new AnalyticsClient() - async function downloadFiles() { const promises = [] for (let url of FILE_URLS) { @@ -72,12 +70,8 @@ async function init(type) { return } } - client.capture({ - distinctId: "cli", - event: AnalyticsEvents.SelfHostInit, - properties: { - type, - }, + captureEvent(AnalyticsEvents.SelfHostInit, { + type, }) await downloadFiles() const config = isQuick ? makeEnv.QUICK_CONFIG : {} diff --git a/packages/cli/src/plugins/index.js b/packages/cli/src/plugins/index.js index d184c6e70a..66cca8c19d 100644 --- a/packages/cli/src/plugins/index.js +++ b/packages/cli/src/plugins/index.js @@ -1,5 +1,5 @@ const Command = require("../structures/Command") -const { CommandWords } = require("../constants") +const { CommandWords, AnalyticsEvents } = require("../constants") const { getSkeleton, fleshOutSkeleton } = require("./skeleton") const questions = require("../questions") const fs = require("fs") @@ -8,6 +8,7 @@ const { validate } = require("@budibase/backend-core/plugins") const { runPkgCommand } = require("../exec") const { join } = require("path") const { success, error, info, moveDirectory } = require("../utils") +const { captureEvent } = require("../events") function checkInPlugin() { if (!fs.existsSync("package.json")) { @@ -58,7 +59,7 @@ async function init(opts) { ) return } - const desc = await questions.string( + const description = await questions.string( "Description", `An amazing Budibase ${type}!` ) @@ -67,7 +68,7 @@ async function init(opts) { // get the skeleton console.log(info("Retrieving project...")) await getSkeleton(type, name) - await fleshOutSkeleton(type, name, desc, version) + await fleshOutSkeleton(type, name, description, version) console.log(info("Installing dependencies...")) await runPkgCommand("install", join(process.cwd(), name)) // if no parent directory desired move to cwd @@ -77,6 +78,12 @@ async function init(opts) { } else { console.log(info(`Plugin created in directory "${name}"`)) } + captureEvent(AnalyticsEvents.PluginInit, { + type, + name, + description, + version, + }) } async function verify() { diff --git a/packages/server/src/api/controllers/plugin/index.ts b/packages/server/src/api/controllers/plugin/index.ts index 0cd074e16b..f560572082 100644 --- a/packages/server/src/api/controllers/plugin/index.ts +++ b/packages/server/src/api/controllers/plugin/index.ts @@ -8,9 +8,10 @@ import { uploadDirectory, deleteFolder, } from "@budibase/backend-core/objectStore" -import { PluginType, FileType, PluginSource } from "@budibase/types" +import { PluginType, FileType, PluginSource, Plugin } from "@budibase/types" import env from "../../../environment" import { ClientAppSocket } from "../../../websocket" +import { events } from "@budibase/backend-core" export async function getPlugins(type?: PluginType) { const db = getGlobalDB() @@ -113,11 +114,12 @@ export async function destroy(ctx: any) { const { pluginId } = ctx.params try { - const plugin = await db.get(pluginId) + const plugin: Plugin = await db.get(pluginId) const bucketPath = `${plugin.name}/` await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath) await db.remove(pluginId, plugin._rev) + await events.plugin.deleted(plugin) } catch (err: any) { const errMsg = err?.message ? err?.message : err @@ -131,7 +133,7 @@ export async function destroy(ctx: any) { export async function storePlugin( metadata: any, directory: any, - source?: string + source?: PluginSource ) { const db = getGlobalDB() const version = metadata.package.version, @@ -173,7 +175,7 @@ export async function storePlugin( } catch (err) { rev = undefined } - let doc = { + let doc: Plugin = { _id: pluginId, _rev: rev, ...metadata, @@ -192,6 +194,7 @@ export async function storePlugin( } const response = await db.put(doc) + await events.plugin.imported(doc) ClientAppSocket.emit("plugin-update", { name, hash }) return { ...doc, @@ -199,7 +202,7 @@ export async function storePlugin( } } -export async function processPlugin(plugin: FileType, source?: string) { +export async function processPlugin(plugin: FileType, source?: PluginSource) { const { metadata, directory } = await fileUpload(plugin) validate(metadata?.schema) diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index 77785c72e4..1f8bb4a84f 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -1,3 +1,4 @@ export * from "./config" export * from "./user" export * from "./userGroup" +export * from "./plugin" diff --git a/packages/types/src/documents/plugin/index.ts b/packages/types/src/documents/global/plugin.ts similarity index 52% rename from packages/types/src/documents/plugin/index.ts rename to packages/types/src/documents/global/plugin.ts index 7fbfececd6..8b9607c41d 100644 --- a/packages/types/src/documents/plugin/index.ts +++ b/packages/types/src/documents/global/plugin.ts @@ -1,3 +1,5 @@ +import { Document } from "../document" + export enum PluginType { DATASOURCE = "datasource", COMPONENT = "component", @@ -14,4 +16,17 @@ export interface FileType { name: string } +export interface Plugin extends Document { + description: string + name: string + version: string + jsUrl?: string + source: PluginSource + package: { [key: string]: any } + schema: { + type: PluginType + [key: string]: any + } +} + export const PLUGIN_TYPE_ARR = Object.values(PluginType) diff --git a/packages/types/src/documents/index.ts b/packages/types/src/documents/index.ts index 70e4dee1aa..47ec48f49c 100644 --- a/packages/types/src/documents/index.ts +++ b/packages/types/src/documents/index.ts @@ -1,7 +1,6 @@ export * from "./account" export * from "./app" export * from "./global" -export * from "./plugin" export * from "./platform" export * from "./document" export * from "./pouch" diff --git a/packages/types/src/sdk/events/datasource.ts b/packages/types/src/sdk/events/datasource.ts index 20d1b78fbb..1d07cf055a 100644 --- a/packages/types/src/sdk/events/datasource.ts +++ b/packages/types/src/sdk/events/datasource.ts @@ -3,14 +3,17 @@ import { BaseEvent } from "./event" export interface DatasourceCreatedEvent extends BaseEvent { datasourceId: string source: string + custom: boolean } export interface DatasourceUpdatedEvent extends BaseEvent { datasourceId: string source: string + custom: boolean } export interface DatasourceDeletedEvent extends BaseEvent { datasourceId: string source: string + custom: boolean } diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index d7086370ec..de56740e44 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -158,6 +158,11 @@ export enum Event { USER_GROUP_USERS_REMOVED = "user_group:users_deleted", USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited", USER_GROUP_ONBOARDING = "user_group:onboarding_added", + + // PLUGIN + PLUGIN_INIT = "plugin:init", + PLUGIN_IMPORTED = "plugin:imported", + PLUGIN_DELETED = "plugin:deleted", } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/index.ts b/packages/types/src/sdk/events/index.ts index 88d5a12e6e..cc0c2b9aa1 100644 --- a/packages/types/src/sdk/events/index.ts +++ b/packages/types/src/sdk/events/index.ts @@ -19,3 +19,4 @@ export * from "./account" export * from "./backfill" export * from "./identification" export * from "./userGroup" +export * from "./plugin" diff --git a/packages/types/src/sdk/events/plugin.ts b/packages/types/src/sdk/events/plugin.ts new file mode 100644 index 0000000000..a32589493a --- /dev/null +++ b/packages/types/src/sdk/events/plugin.ts @@ -0,0 +1,26 @@ +import { BaseEvent } from "./event" +import { PluginSource, PluginType } from "../../" + +export interface PluginInitEvent extends BaseEvent { + type: PluginType + name: string + version: string + description: string +} + +export interface PluginImportedEvent extends BaseEvent { + pluginId: string + type: PluginType + source: PluginSource + name: string + version: string + description: string +} + +export interface PluginDeletedEvent extends BaseEvent { + pluginId: string + type: PluginType + name: string + version: string + description: string +}