diff --git a/packages/backend-core/src/analytics/constants.js b/packages/backend-core/src/analytics/constants.js deleted file mode 100644 index 4c5b69311f..0000000000 --- a/packages/backend-core/src/analytics/constants.js +++ /dev/null @@ -1,57 +0,0 @@ -const Events = { - // - BUILDER: { - STARTED: "Builder Started", - }, - COMPONENT: { - CREATED: "Added Component", - }, - DATASOURCE: { - CREATED: "Datasource Created", - UPDATED: "Datasource Updated", - }, - QUERIES: { - REST: "REST Queries Imported", - }, - TABLE: { - CREATED: "Table Created", - }, - VIEW: { - CREATED: "View Created", - ADDED_FILTER: "Added View Filter", - ADDED_CALCULATE: "Added View Calculate", - }, - SCREEN: { - CREATED: "Screen Created", - }, - AUTOMATION: { - CREATED: "Automation Created", - SAVED: "Automation Saved", - BLOCK_ADDED: "Added Automation Block", - }, - NPS: { - SUBMITTED: "budibase:feedback_submitted", - }, - APP: { - CREATED: "budibase:app_created", - PUBLISHED: "budibase:app_published", - UNPUBLISHED: "budibase:app_unpublished", - }, - ANALYTICS: { - OPT_IN: "budibase:analytics_opt_in", - OPT_OUT: "budibase:analytics_opt_out", - }, - USER: { - INVITE: "budibase:portal_user_invite", - }, - SMTP: { - SAVED: "budibase:smtp_saved", - }, - SSO: { - SAVED: "budibase:sso_saved", - }, -} - -module.exports = { - Events, -} diff --git a/packages/backend-core/src/analytics/index.js b/packages/backend-core/src/analytics/index.js deleted file mode 100644 index 9aa688fae0..0000000000 --- a/packages/backend-core/src/analytics/index.js +++ /dev/null @@ -1,6 +0,0 @@ -const Analytics = require("./analytics") -const { Events } = require("./constants") - -module.exports = new Analytics() -// exports = module.exports -exports.Events = Events diff --git a/packages/backend-core/src/analytics/analytics.js b/packages/backend-core/src/events/analytics/analytics.js similarity index 73% rename from packages/backend-core/src/analytics/analytics.js rename to packages/backend-core/src/events/analytics/analytics.js index 820309cea9..03a17b24a4 100644 --- a/packages/backend-core/src/analytics/analytics.js +++ b/packages/backend-core/src/events/analytics/analytics.js @@ -1,5 +1,5 @@ const PosthogClient = require("./posthog") -const env = require("../environment") +const env = require("../../environment") class Analytics { constructor() { @@ -19,9 +19,11 @@ class Analytics { this.posthog.updateUser(userId, properties) } - captureEvent(userId, eventName, props = {}) { + captureEvent(eventName, properties) { if (!this.isEnabled) return - this.posthog.capture(userId, eventName, props) + // TODO: get the user id from context + const userId = "TESTING_USER_ID" + this.posthog.capture(userId, eventName, properties) } shutdown() { diff --git a/packages/backend-core/src/events/analytics/index.js b/packages/backend-core/src/events/analytics/index.js new file mode 100644 index 0000000000..0e20ad7d80 --- /dev/null +++ b/packages/backend-core/src/events/analytics/index.js @@ -0,0 +1,7 @@ +const Analytics = require("./analytics") + +const analytics = new Analytics() + +module.exports = { + analytics, +} diff --git a/packages/backend-core/src/analytics/posthog.js b/packages/backend-core/src/events/analytics/posthog.js similarity index 100% rename from packages/backend-core/src/analytics/posthog.js rename to packages/backend-core/src/events/analytics/posthog.js diff --git a/packages/backend-core/src/events/constants.js b/packages/backend-core/src/events/constants.js new file mode 100644 index 0000000000..b991c163df --- /dev/null +++ b/packages/backend-core/src/events/constants.js @@ -0,0 +1,170 @@ +exports.Events = { + /** + ------------------ + USER + ------------------ + */ + + USER_CREATED: "user:created", + USER_UPDATED: "user:updated", + USER_DELETED: "user:deleted", + USER_PASSWORD_RESET: "user:password:reset", + + // PERMISSIONS + USER_PERMISSION_ADMIN_ASSIGNED: "user:permission:admin:assigned", + USER_PERMISSION_ADMIN_REMOVED: "user:permission:admin:removed", + USER_PERMISSION_BUILDER_ASSIGNED: "user:permission:builder:assigned", + USER_PERMISSION_BUILDER_REMOVED: "user:permission:builder:removed", + + // INVITE + USER_INVITED: "user:invited", + USER_INVITED_ACCEPTED: "user:invite:accepted", + + // SELF + USER_SELF_UPDATED: "user:self:updated", + USER_SELF_PASSWORD_UPDATED: "user:self:password:updated", + USER_PASSWORD_RESET_REQUESTED: "user:password:reset:requested", + + /** + ------------------ + ADMIN + ------------------ + */ + + // EMAIL + EMAIL_SMTP_CREATED: "email:smtp:created", + EMAIL_SMTP_UPDATED: "email:smtp:updated", + + // AUTH + AUTH_SSO_CREATED: "auth:sso:created", + AUTH_SSO_UPDATED: "auth:sso:updated", + AUTH_SSO_ACTIVATED: "auth:sso:activated", + AUTH_SSO_DEACTIVATED: "auth:sso:deactivated", + + // ORG + ORG_NAME_UPDATED: "org:info:name:updated", + ORG_LOGO_UPDATED: "org:info:logo:updated", + ORG_PLATFORM_URL_UPDATED: "org:platformurl:updated", + + // UPDATE + UPDATE_VERSION_CHECKED: "version:checked", + + // ANALYTICS + ANALYTICS_OPT_OUT: "analytics:opt:out", + + /** + ------------------ + APP + ------------------ + */ + + // APP + APP_CREATED: "app:created", + APP_UPDATED: "app:updated", + APP_DELETED: "app:deleted", + APP_PUBLISHED: "app:published", + APP_UNPUBLISHED: "app:unpublished", + APP_IMPORTED: "app:imported", + APP_VERSION_UPDATED: "app:version:updated", + APP_REVERTED: "app:reverted", + APP_EXPORTED: "app:exported", + + // ROLE + APP_ROLE_CREATED: "app:role:created", + APP_ROLE_DELETED: "app:role:deleted", + APP_ROLE_ASSIGNED: "app:role:assigned", + + // CLIENT + CLIENT_SERVED: "client:served", + + /** + ------------------ + DATA + ------------------ + */ + + // DATASOURCE + DATASOURCE_CREATED: "datasource:created", + DATASOURCE_UPDATED: "datasource:updated", + DATASOURCE_DELETED: "datasource:deleted", + + // QUERY + QUERY_CREATED: "query:created", + QUERY_UPDATED: "query:updated", + QUERY_DELETED: "query:deleted", + QUERY_IMPORTED: "query:imported", + QUERY_RUN: "query:run", + QUERY_PREVIEW: "query:preview", + + // TABLE + TABLE_CREATED: "table:created", + TABLE_UPDATED: "table:updated", + TABLE_DELETED: "table:deleted", + TABLE_EXPORTED: "table:exported", + TABLE_IMPORTED: "table:imported", + TABLE_DATA_IMPORTED: "table:data:imported", + TABLE_PERMISSION_UPDATED: "table:permission:updated", + + // VIEW + VIEW_CREATED: "view:created", + VIEW_UPDATED: "view:updated", + VIEW_DELETED: "view:deleted", + VIEW_EXPORTED: "view:exported", + VIEW_FILTER_CREATED: "view:filter:created", + VIEW_FILTER_DELETED: "view:filter:created", + VIEW_CALCULATION_CREATED: "view:calculation:created", + VIEW_CALCULATION_DELETED: "view:calculation:created", + + // ROW + ROW_CREATED: "row:created", + ROW_UPDATED: "row:updated", + ROW_DELETED: "row:deleted", + ROW_IMPORTED: "row:imported", + + /** + ------------------ + DESIGN + ------------------ + */ + + // BUILDER + BUILDER_SERVED: "builder:served", + + // COMPONENT + COMPONENT_CREATED: "component:created", + COMPONENT_DELETED: "component:deleted", + + // SCREEN + SCREEN_CREATED: "screen:created", + SCREEN_DELETED: "screen:deleted", + + // LAYOUT + LAYOUT_CREATED: "layout:created", + LAYOUT_DELETED: "layout:deleted", + + /** + ------------------ + AUTOMATE + ------------------ + */ + + AUTOMATION_CREATED: "automation:created", + AUTOMATION_DELETED: "automation:deleted", + AUTOMATION_TESTED: "automation:tested", + AUTOMATION_RUN: "automation:run", + AUTOMATION_STEP_CREATED: "automation:step:created", + AUTOMATION_STEP_DELETED: "automation:step:deleted", + + /** + ------------------ + MISC + ------------------ + */ + + // NPS + NPS_SUBMITTED: "nps:submitted", + + // AUTH + AUTH_LOGIN: "auth:login", + AUTH_LOGOUT: "auth:logout", +} diff --git a/packages/backend-core/src/events/events.js b/packages/backend-core/src/events/events.js new file mode 100644 index 0000000000..e8b54910a6 --- /dev/null +++ b/packages/backend-core/src/events/events.js @@ -0,0 +1,494 @@ +const { getTenantId } = require("../context") +const { analytics } = require("./analytics") +const { Events } = require("./constants") + +const logEvent = messsage => { + const tenantId = getTenantId() + const userId = getTenantId() // TODO + console.log(`[tenant=${tenantId}] [user=${userId}] ${messsage}`) +} + +const processEvent = (event, properties) => { + // logging + logEvent(event) + + // analytics + analytics.captureEvent(event, properties) +} + +/** +------------------ + USER +------------------ +*/ + +exports.userCreated = () => { + const properties = {} + processEvent(Events.USER_CREATED, properties) +} + +exports.userUpdated = () => { + const properties = {} + processEvent(Events.USER_UPDATED, properties) +} + +exports.userDeleted = () => { + const properties = {} + processEvent(Events.USER_DELETED, properties) +} + +exports.userForcePasswordReset = () => { + const properties = {} + processEvent(Events.USER_PASSWORD_RESET, properties) +} + +// PERMISSIONS + +exports.userPermissionAdminAssigned = () => { + const properties = {} + processEvent(Events.USER_PERMISSION_ADMIN_ASSIGNED, properties) +} + +exports.userPermissionAdminRemoved = () => { + const properties = {} + processEvent(Events.USER_PERMISSION_ADMIN_REMOVED, properties) +} + +exports.userPermissionBuilderAssigned = () => { + const properties = {} + processEvent(Events.USER_PERMISSION_BUILDER_ASSIGNED, properties) +} + +exports.userPermissionBuilderRemoved = () => { + const properties = {} + processEvent(Events.USER_PERMISSION_BUILDER_REMOVED, properties) +} + +// INVITE + +exports.userInvited = () => { + const properties = {} + processEvent(Events.USER_INVITED, properties) +} + +exports.userInviteAccepted = () => { + const properties = {} + processEvent(Events.USER_INVITED_ACCEPTED, properties) +} + +// SELF + +exports.userSelfUpdated = () => { + const properties = {} + processEvent(Events.USER_SELF_UPDATED, properties) +} + +exports.userSelfPasswordUpdated = () => { + const properties = {} + processEvent(Events.USER_SELF_PASSWORD_UPDATED, properties) +} + +exports.userPasswordResetRequested = () => { + const properties = {} + processEvent(Events.USER_PASSWORD_RESET_REQUESTED, properties) +} + +/** + ------------------ + ADMIN + ------------------ +*/ + +// EMAIL + +exports.emailSMTPCreated = () => { + const properties = {} + processEvent(Events.EMAIL_SMTP_CREATED, properties) +} + +exports.emailSMTPUpdated = () => { + const properties = {} + processEvent(Events.EMAIL_SMTP_UPDATED, properties) +} + +// AUTH + +exports.authSSOCreated = () => { + const properties = {} + processEvent(Events.AUTH_SSO_CREATED, properties) +} + +exports.authSSOUpdated = () => { + const properties = {} + processEvent(Events.AUTH_SSO_UPDATED, properties) +} + +exports.authSSOActivated = () => { + const properties = {} + processEvent(Events.AUTH_SSO_ACTIVATED, properties) +} + +exports.authSSODeactivated = () => { + const properties = {} + processEvent(Events.AUTH_SSO_DEACTIVATED, properties) +} + +// ORG + +exports.orgNameUpdated = () => { + const properties = {} + processEvent(Events.ORG_NAME_UPDATED, properties) +} + +exports.orgLogoUpdated = () => { + const properties = {} + processEvent(Events.ORG_LOGO_UPDATED, properties) +} + +exports.orgPlatformURLUpdated = () => { + const properties = {} + processEvent(Events.ORG_PLATFORM_URL_UPDATED, properties) +} + +// UPDATE + +exports.updateVersionChecked = () => { + const properties = {} + processEvent(Events.UPDATE_VERSION_CHECKED, properties) +} + +// ANALYTICS + +exports.analyticsOptOut = () => { + const properties = {} + processEvent(Events.ANALYTICS_OPT_OUT, properties) +} + +/** + ------------------ + APP + ------------------ +*/ + +// APP + +exports.appCreated = () => { + const properties = {} + processEvent(Events.APP_CREATED, properties) +} + +exports.appUpdated = () => { + const properties = {} + processEvent(Events.APP_UPDATED, properties) +} + +exports.appDeleted = () => { + const properties = {} + processEvent(Events.APP_DELETED, properties) +} + +exports.appPublished = () => { + const properties = {} + processEvent(Events.APP_PUBLISHED, properties) +} + +exports.appUnpublished = () => { + const properties = {} + processEvent(Events.APP_UNPUBLISHED, properties) +} + +exports.appImported = () => { + const properties = {} + processEvent(Events.APP_IMPORTED, properties) +} + +exports.appVersionUpdated = () => { + const properties = {} + processEvent(Events.APP_VERSION_UPDATED, properties) +} + +exports.appReverted = () => { + const properties = {} + processEvent(Events.APP_REVERTED, properties) +} + +exports.appExported = () => { + const properties = {} + processEvent(Events.APP_EXPORTED, properties) +} + +// ROLE + +exports.appRoleCreated = () => { + const properties = {} + processEvent(Events.APP_ROLE_CREATED, properties) +} + +exports.appRoleDeleted = () => { + const properties = {} + processEvent(Events.APP_ROLE_DELETED, properties) +} + +exports.appRoleAssigned = () => { + const properties = {} + processEvent(Events.APP_ROLE_ASSIGNED, properties) +} + +// CLIENT + +exports.clientServed = () => { + const properties = {} + processEvent(Events.CLIENT_SERVED, properties) +} + +/** + ------------------ + DATA + ------------------ +*/ + +// DATASOURCE + +exports.datasourceCreated = () => { + const properties = {} + processEvent(Events.DATASOURCE_CREATED, properties) +} + +exports.datasourceUpdated = () => { + const properties = {} + processEvent(Events.DATASOURCE_UPDATED, properties) +} + +exports.datasourceDeleted = () => { + const properties = {} + processEvent(Events.DATASOURCE_DELETED, properties) +} + +// QUERY + +exports.queryCreated = () => { + const properties = {} + processEvent(Events.QUERY_CREATED, properties) +} + +exports.queryUpdated = () => { + const properties = {} + processEvent(Events.QUERY_UPDATED, properties) +} + +exports.queryDeleted = () => { + const properties = {} + processEvent(Events.QUERY_DELETED, properties) +} + +exports.queryImported = () => { + const properties = {} + processEvent(Events.QUERY_DELETED, properties) +} + +exports.queryRun = () => { + const properties = {} + processEvent(Events.QUERY_DELETED, properties) +} + +exports.queryPreview = () => { + const properties = {} + processEvent(Events.QUERY_DELETED, properties) +} + +// TABLE + +exports.tableCreated = () => { + const properties = {} + processEvent(Events.TABLE_CREATED, properties) +} + +exports.tableUpdated = () => { + const properties = {} + processEvent(Events.TABLE_UPDATED, properties) +} + +exports.tableDeleted = () => { + const properties = {} + processEvent(Events.TABLE_DELETED, properties) +} + +exports.tableExported = () => { + const properties = {} + processEvent(Events.TABLE_EXPORTED, properties) +} + +exports.tableImported = () => { + const properties = {} + processEvent(Events.TABLE_IMPORTED, properties) +} + +exports.tablePermissionUpdated = () => { + const properties = {} + processEvent(Events.TABLE_PERMISSION_UPDATED, properties) +} + +// VIEW + +exports.viewCreated = () => { + const properties = {} + processEvent(Events.VIEW_CREATED, properties) +} + +exports.viewUpdated = () => { + const properties = {} + processEvent(Events.VIEW_UPDATED, properties) +} + +exports.viewDeleted = () => { + const properties = {} + processEvent(Events.VIEW_DELETED, properties) +} + +exports.viewExported = () => { + const properties = {} + processEvent(Events.VIEW_EXPORTED, properties) +} + +exports.viewFilterCreated = () => { + const properties = {} + processEvent(Events.VIEW_FILTER_CREATED, properties) +} + +exports.viewFilterDeleted = () => { + const properties = {} + processEvent(Events.VIEW_FILTER_DELETED, properties) +} + +exports.viewCalculationCreated = () => { + const properties = {} + processEvent(Events.VIEW_CALCULATION_CREATED, properties) +} + +exports.viewCalculationDeleted = () => { + const properties = {} + processEvent(Events.VIEW_CALCULATION_DELETED, properties) +} + +// ROW + +exports.rowCreated = () => { + const properties = {} + processEvent(Events.ROW_CREATED, properties) +} + +exports.rowImported = () => { + const properties = {} + processEvent(Events.ROW_IMPORTED, properties) + exports.rowCreated() +} + +exports.rowUpdated = () => { + const properties = {} + processEvent(Events.ROW_UPDATED, properties) +} + +exports.rowDeleted = () => { + const properties = {} + processEvent(Events.ROW_DELETED, properties) +} + +/** + ------------------ + DESIGN + ------------------ +*/ + +// BUILDER + +exports.builderServed = () => { + const properties = {} + processEvent(Events.BUILDER_SERVED, properties) +} + +// COMPONENTS - are captured in the UI only + +// SCREEN + +exports.screenCreated = () => { + const properties = {} + processEvent(Events.SCREEN_CREATED, properties) +} + +exports.screenDeleted = () => { + const properties = {} + processEvent(Events.SCREEN_DELETED, properties) +} + +// LAYOUT + +exports.layoutCreated = () => { + const properties = {} + processEvent(Events.LAYOUT_CREATED, properties) +} + +exports.layoutDeleted = () => { + const properties = {} + processEvent(Events.LAYOUT_DELETED, properties) +} + +/** + ------------------ + AUTOMATE + ------------------ +*/ + +exports.automationCreated = () => { + const properties = {} + processEvent(Events.AUTOMATION_CREATED, properties) +} + +exports.automationDeleted = () => { + const properties = {} + processEvent(Events.AUTOMATION_DELETED, properties) +} + +exports.automationTested = () => { + const properties = {} + processEvent(Events.AUTOMATION_TESTED, properties) +} + +exports.automationRun = () => { + const properties = {} + processEvent(Events.AUTOMATION_RUN, properties) +} + +exports.automationStepCreated = () => { + const properties = {} + processEvent(Events.AUTOMATION_STEP_CREATED, properties) +} + +exports.automationStepDeleted = () => { + const properties = {} + processEvent(Events.AUTOMATION_STEP_DELETED, properties) +} + +/** + ------------------ + MISC + ------------------ +*/ + +// NPS + +exports.npsSubmitted = () => { + const properties = {} + processEvent(Events.NPS_SUBMITTED, properties) +} + +// AUTH + +exports.login = () => { + const properties = {} + processEvent(Events.AUTH_LOGIN, properties) +} + +exports.logout = () => { + const properties = {} + processEvent(Events.AUTH_LOGOUT, properties) +} diff --git a/packages/backend-core/src/events/index.js b/packages/backend-core/src/events/index.js new file mode 100644 index 0000000000..e91cc25703 --- /dev/null +++ b/packages/backend-core/src/events/index.js @@ -0,0 +1,2 @@ +const events = require("./events") +module.exports = events diff --git a/packages/backend-core/src/index.js b/packages/backend-core/src/index.js index f403b44a3d..2e5249a653 100644 --- a/packages/backend-core/src/index.js +++ b/packages/backend-core/src/index.js @@ -20,5 +20,5 @@ module.exports = { accounts: require("./cloud/accounts"), tenancy: require("./tenancy"), featureFlags: require("./featureFlags"), - analytics: require("./analytics"), + events: require("./events"), } diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index 999f322563..1117d15841 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -11,6 +11,7 @@ const { integrations } = require("../../integrations") const { getDatasourceAndQuery } = require("./row/utils") const { invalidateDynamicVariables } = require("../../threads/utils") const { getAppDB } = require("@budibase/backend-core/context") +const { events } = require("@budibase/backend-core") exports.fetch = async function (ctx) { // Get internal tables @@ -142,6 +143,7 @@ exports.save = async function (ctx) { } const dbResp = await db.put(datasource) + events.datasourceCreated(datasource) datasource._rev = dbResp.rev // Drain connection pools when configuration is changed