Merge pull request #7774 from Budibase/events/plugins

Plugin init, imported and deleted events
This commit is contained in:
Michael Drury 2022-09-15 12:55:40 +02:00 committed by GitHub
commit 5e530c7374
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 138 additions and 18 deletions

View File

@ -5,8 +5,15 @@ import {
DatasourceCreatedEvent, DatasourceCreatedEvent,
DatasourceUpdatedEvent, DatasourceUpdatedEvent,
DatasourceDeletedEvent, DatasourceDeletedEvent,
SourceName,
} from "@budibase/types" } 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( export async function created(
datasource: Datasource, datasource: Datasource,
timestamp?: string | number timestamp?: string | number
@ -14,6 +21,7 @@ export async function created(
const properties: DatasourceCreatedEvent = { const properties: DatasourceCreatedEvent = {
datasourceId: datasource._id as string, datasourceId: datasource._id as string,
source: datasource.source, source: datasource.source,
custom: isCustom(datasource),
} }
await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp) await publishEvent(Event.DATASOURCE_CREATED, properties, timestamp)
} }
@ -22,6 +30,7 @@ export async function updated(datasource: Datasource) {
const properties: DatasourceUpdatedEvent = { const properties: DatasourceUpdatedEvent = {
datasourceId: datasource._id as string, datasourceId: datasource._id as string,
source: datasource.source, source: datasource.source,
custom: isCustom(datasource),
} }
await publishEvent(Event.DATASOURCE_UPDATED, properties) await publishEvent(Event.DATASOURCE_UPDATED, properties)
} }
@ -30,6 +39,7 @@ export async function deleted(datasource: Datasource) {
const properties: DatasourceDeletedEvent = { const properties: DatasourceDeletedEvent = {
datasourceId: datasource._id as string, datasourceId: datasource._id as string,
source: datasource.source, source: datasource.source,
custom: isCustom(datasource),
} }
await publishEvent(Event.DATASOURCE_DELETED, properties) await publishEvent(Event.DATASOURCE_DELETED, properties)
} }

View File

@ -18,3 +18,4 @@ export * as view from "./view"
export * as installation from "./installation" export * as installation from "./installation"
export * as backfill from "./backfill" export * as backfill from "./backfill"
export * as group from "./group" export * as group from "./group"
export * as plugin from "./plugin"

View File

@ -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)
}

View File

@ -1,3 +1,5 @@
const { Event } = require("@budibase/types")
exports.CommandWords = { exports.CommandWords = {
BACKUPS: "backups", BACKUPS: "backups",
HOSTING: "hosting", HOSTING: "hosting",
@ -15,6 +17,7 @@ exports.AnalyticsEvents = {
OptOut: "analytics:opt:out", OptOut: "analytics:opt:out",
OptIn: "analytics:opt:in", OptIn: "analytics:opt:in",
SelfHostInit: "hosting:init", SelfHostInit: "hosting:init",
PluginInit: Event.PLUGIN_INIT,
} }
exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS" exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"

View File

@ -0,0 +1,11 @@
const AnalyticsClient = require("./analytics/Client")
const client = new AnalyticsClient()
exports.captureEvent = (event, properties) => {
client.capture({
distinctId: "cli",
event,
properties,
})
}

View File

@ -13,7 +13,7 @@ const fs = require("fs")
const compose = require("docker-compose") const compose = require("docker-compose")
const makeEnv = require("./makeEnv") const makeEnv = require("./makeEnv")
const axios = require("axios") const axios = require("axios")
const AnalyticsClient = require("../analytics/Client") const { captureEvent } = require("../events")
const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"] const BUDIBASE_SERVICES = ["app-service", "worker-service", "proxy-service"]
const ERROR_FILE = "docker-error.log" 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 DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data"
const client = new AnalyticsClient()
async function downloadFiles() { async function downloadFiles() {
const promises = [] const promises = []
for (let url of FILE_URLS) { for (let url of FILE_URLS) {
@ -72,12 +70,8 @@ async function init(type) {
return return
} }
} }
client.capture({ captureEvent(AnalyticsEvents.SelfHostInit, {
distinctId: "cli", type,
event: AnalyticsEvents.SelfHostInit,
properties: {
type,
},
}) })
await downloadFiles() await downloadFiles()
const config = isQuick ? makeEnv.QUICK_CONFIG : {} const config = isQuick ? makeEnv.QUICK_CONFIG : {}

View File

@ -1,5 +1,5 @@
const Command = require("../structures/Command") const Command = require("../structures/Command")
const { CommandWords } = require("../constants") const { CommandWords, AnalyticsEvents } = require("../constants")
const { getSkeleton, fleshOutSkeleton } = require("./skeleton") const { getSkeleton, fleshOutSkeleton } = require("./skeleton")
const questions = require("../questions") const questions = require("../questions")
const fs = require("fs") const fs = require("fs")
@ -8,6 +8,7 @@ const { validate } = require("@budibase/backend-core/plugins")
const { runPkgCommand } = require("../exec") const { runPkgCommand } = require("../exec")
const { join } = require("path") const { join } = require("path")
const { success, error, info, moveDirectory } = require("../utils") const { success, error, info, moveDirectory } = require("../utils")
const { captureEvent } = require("../events")
function checkInPlugin() { function checkInPlugin() {
if (!fs.existsSync("package.json")) { if (!fs.existsSync("package.json")) {
@ -58,7 +59,7 @@ async function init(opts) {
) )
return return
} }
const desc = await questions.string( const description = await questions.string(
"Description", "Description",
`An amazing Budibase ${type}!` `An amazing Budibase ${type}!`
) )
@ -67,7 +68,7 @@ async function init(opts) {
// get the skeleton // get the skeleton
console.log(info("Retrieving project...")) console.log(info("Retrieving project..."))
await getSkeleton(type, name) await getSkeleton(type, name)
await fleshOutSkeleton(type, name, desc, version) await fleshOutSkeleton(type, name, description, version)
console.log(info("Installing dependencies...")) console.log(info("Installing dependencies..."))
await runPkgCommand("install", join(process.cwd(), name)) await runPkgCommand("install", join(process.cwd(), name))
// if no parent directory desired move to cwd // if no parent directory desired move to cwd
@ -77,6 +78,12 @@ async function init(opts) {
} else { } else {
console.log(info(`Plugin created in directory "${name}"`)) console.log(info(`Plugin created in directory "${name}"`))
} }
captureEvent(AnalyticsEvents.PluginInit, {
type,
name,
description,
version,
})
} }
async function verify() { async function verify() {

View File

@ -8,9 +8,10 @@ import {
uploadDirectory, uploadDirectory,
deleteFolder, deleteFolder,
} from "@budibase/backend-core/objectStore" } 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 env from "../../../environment"
import { ClientAppSocket } from "../../../websocket" import { ClientAppSocket } from "../../../websocket"
import { events } from "@budibase/backend-core"
export async function getPlugins(type?: PluginType) { export async function getPlugins(type?: PluginType) {
const db = getGlobalDB() const db = getGlobalDB()
@ -113,11 +114,12 @@ export async function destroy(ctx: any) {
const { pluginId } = ctx.params const { pluginId } = ctx.params
try { try {
const plugin = await db.get(pluginId) const plugin: Plugin = await db.get(pluginId)
const bucketPath = `${plugin.name}/` const bucketPath = `${plugin.name}/`
await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath) await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
await db.remove(pluginId, plugin._rev) await db.remove(pluginId, plugin._rev)
await events.plugin.deleted(plugin)
} catch (err: any) { } catch (err: any) {
const errMsg = err?.message ? err?.message : err const errMsg = err?.message ? err?.message : err
@ -131,7 +133,7 @@ export async function destroy(ctx: any) {
export async function storePlugin( export async function storePlugin(
metadata: any, metadata: any,
directory: any, directory: any,
source?: string source?: PluginSource
) { ) {
const db = getGlobalDB() const db = getGlobalDB()
const version = metadata.package.version, const version = metadata.package.version,
@ -173,7 +175,7 @@ export async function storePlugin(
} catch (err) { } catch (err) {
rev = undefined rev = undefined
} }
let doc = { let doc: Plugin = {
_id: pluginId, _id: pluginId,
_rev: rev, _rev: rev,
...metadata, ...metadata,
@ -192,6 +194,7 @@ export async function storePlugin(
} }
const response = await db.put(doc) const response = await db.put(doc)
await events.plugin.imported(doc)
ClientAppSocket.emit("plugin-update", { name, hash }) ClientAppSocket.emit("plugin-update", { name, hash })
return { return {
...doc, ...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) const { metadata, directory } = await fileUpload(plugin)
validate(metadata?.schema) validate(metadata?.schema)

View File

@ -1,3 +1,4 @@
export * from "./config" export * from "./config"
export * from "./user" export * from "./user"
export * from "./userGroup" export * from "./userGroup"
export * from "./plugin"

View File

@ -1,3 +1,5 @@
import { Document } from "../document"
export enum PluginType { export enum PluginType {
DATASOURCE = "datasource", DATASOURCE = "datasource",
COMPONENT = "component", COMPONENT = "component",
@ -14,4 +16,17 @@ export interface FileType {
name: string 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) export const PLUGIN_TYPE_ARR = Object.values(PluginType)

View File

@ -1,7 +1,6 @@
export * from "./account" export * from "./account"
export * from "./app" export * from "./app"
export * from "./global" export * from "./global"
export * from "./plugin"
export * from "./platform" export * from "./platform"
export * from "./document" export * from "./document"
export * from "./pouch" export * from "./pouch"

View File

@ -3,14 +3,17 @@ import { BaseEvent } from "./event"
export interface DatasourceCreatedEvent extends BaseEvent { export interface DatasourceCreatedEvent extends BaseEvent {
datasourceId: string datasourceId: string
source: string source: string
custom: boolean
} }
export interface DatasourceUpdatedEvent extends BaseEvent { export interface DatasourceUpdatedEvent extends BaseEvent {
datasourceId: string datasourceId: string
source: string source: string
custom: boolean
} }
export interface DatasourceDeletedEvent extends BaseEvent { export interface DatasourceDeletedEvent extends BaseEvent {
datasourceId: string datasourceId: string
source: string source: string
custom: boolean
} }

View File

@ -158,6 +158,11 @@ export enum Event {
USER_GROUP_USERS_REMOVED = "user_group:users_deleted", USER_GROUP_USERS_REMOVED = "user_group:users_deleted",
USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited", USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited",
USER_GROUP_ONBOARDING = "user_group:onboarding_added", 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 // properties added at the final stage of the event pipeline

View File

@ -19,3 +19,4 @@ export * from "./account"
export * from "./backfill" export * from "./backfill"
export * from "./identification" export * from "./identification"
export * from "./userGroup" export * from "./userGroup"
export * from "./plugin"

View File

@ -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
}