diff --git a/packages/backend-core/src/events/analytics/analytics.js b/packages/backend-core/src/analytics/analytics.js similarity index 94% rename from packages/backend-core/src/events/analytics/analytics.js rename to packages/backend-core/src/analytics/analytics.js index 03a17b24a4..eb8688de51 100644 --- a/packages/backend-core/src/events/analytics/analytics.js +++ b/packages/backend-core/src/analytics/analytics.js @@ -1,5 +1,5 @@ const PosthogClient = require("./posthog") -const env = require("../../environment") +const env = require("../environment") class Analytics { constructor() { diff --git a/packages/backend-core/src/events/analytics/index.js b/packages/backend-core/src/analytics/index.js similarity index 68% rename from packages/backend-core/src/events/analytics/index.js rename to packages/backend-core/src/analytics/index.js index 0e20ad7d80..5a097552e9 100644 --- a/packages/backend-core/src/events/analytics/index.js +++ b/packages/backend-core/src/analytics/index.js @@ -1,7 +1,4 @@ const Analytics = require("./analytics") const analytics = new Analytics() - -module.exports = { - analytics, -} +module.exports = analytics diff --git a/packages/backend-core/src/events/analytics/posthog.js b/packages/backend-core/src/analytics/posthog.js similarity index 100% rename from packages/backend-core/src/events/analytics/posthog.js rename to packages/backend-core/src/analytics/posthog.js diff --git a/packages/backend-core/src/events/constants.js b/packages/backend-core/src/events/constants.js index b991c163df..63d601d0d1 100644 --- a/packages/backend-core/src/events/constants.js +++ b/packages/backend-core/src/events/constants.js @@ -1,35 +1,25 @@ exports.Events = { - /** - ------------------ - USER - ------------------ - */ - + // USER USER_CREATED: "user:created", USER_UPDATED: "user:updated", USER_DELETED: "user:deleted", - USER_PASSWORD_RESET: "user:password:reset", + USER_PASSWORD_FORCE_RESET: "user:password:force: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", + // USER / PERMISSIONS + USER_PERMISSION_ADMIN_ASSIGNED: "user:admin:assigned", + USER_PERMISSION_ADMIN_REMOVED: "user:admin:removed", + USER_PERMISSION_BUILDER_ASSIGNED: "user:builder:assigned", + USER_PERMISSION_BUILDER_REMOVED: "userbuilder:removed", - // INVITE + // USER / INVITE USER_INVITED: "user:invited", USER_INVITED_ACCEPTED: "user:invite:accepted", - // SELF + // USER / SELF USER_SELF_UPDATED: "user:self:updated", USER_SELF_PASSWORD_UPDATED: "user:self:password:updated", USER_PASSWORD_RESET_REQUESTED: "user:password:reset:requested", - - /** - ------------------ - ADMIN - ------------------ - */ + USER_PASSWORD_RESET: "user:password:reset", // EMAIL EMAIL_SMTP_CREATED: "email:smtp:created", @@ -40,49 +30,44 @@ exports.Events = { AUTH_SSO_UPDATED: "auth:sso:updated", AUTH_SSO_ACTIVATED: "auth:sso:activated", AUTH_SSO_DEACTIVATED: "auth:sso:deactivated", + AUTH_LOGIN: "auth:login", + AUTH_LOGOUT: "auth:logout", // ORG ORG_NAME_UPDATED: "org:info:name:updated", ORG_LOGO_UPDATED: "org:info:logo:updated", ORG_PLATFORM_URL_UPDATED: "org:platformurl:updated", - // UPDATE + // ORG / NPS + NPS_SUBMITTED: "nps:submitted", + + // ORG / UPDATE UPDATE_VERSION_CHECKED: "version:checked", - // ANALYTICS + // ORG / 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_TEMPLATE_IMPORTED: "app:template:imported", + APP_FILE_IMPORTED: "app:file:imported", APP_VERSION_UPDATED: "app:version:updated", + APP_VERSION_REVERTED: "app:version:reverted", 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", + ROLE_CREATED: "role:created", + ROLE_DELETED: "role:deleted", + ROLE_ASSIGNED: "role:assigned", - // CLIENT + // APP / CLIENT CLIENT_SERVED: "client:served", - /** - ------------------ - DATA - ------------------ - */ - // DATASOURCE DATASOURCE_CREATED: "datasource:created", DATASOURCE_UPDATED: "datasource:updated", @@ -94,7 +79,7 @@ exports.Events = { QUERY_DELETED: "query:deleted", QUERY_IMPORTED: "query:imported", QUERY_RUN: "query:run", - QUERY_PREVIEW: "query:preview", + QUERY_PREVIEWED: "query:previewed", // TABLE TABLE_CREATED: "table:created", @@ -121,12 +106,6 @@ exports.Events = { ROW_DELETED: "row:deleted", ROW_IMPORTED: "row:imported", - /** - ------------------ - DESIGN - ------------------ - */ - // BUILDER BUILDER_SERVED: "builder:served", @@ -142,12 +121,7 @@ exports.Events = { LAYOUT_CREATED: "layout:created", LAYOUT_DELETED: "layout:deleted", - /** - ------------------ - AUTOMATE - ------------------ - */ - + // AUTOMATION AUTOMATION_CREATED: "automation:created", AUTOMATION_DELETED: "automation:deleted", AUTOMATION_TESTED: "automation:tested", @@ -155,16 +129,6 @@ exports.Events = { 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", + // LICENSING + LICENSING_QUOTA_EXCEEDED: "licensing:quota:exceeded", } diff --git a/packages/backend-core/src/events/events.js b/packages/backend-core/src/events/events.js index e8b54910a6..8a51c602c7 100644 --- a/packages/backend-core/src/events/events.js +++ b/packages/backend-core/src/events/events.js @@ -1,6 +1,5 @@ const { getTenantId } = require("../context") -const { analytics } = require("./analytics") -const { Events } = require("./constants") +const analytics = require("../analytics") const logEvent = messsage => { const tenantId = getTenantId() @@ -8,487 +7,10 @@ const logEvent = messsage => { console.log(`[tenant=${tenantId}] [user=${userId}] ${messsage}`) } -const processEvent = (event, properties) => { +exports.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/handlers/app.js b/packages/backend-core/src/events/handlers/app.js new file mode 100644 index 0000000000..c55a5c15e9 --- /dev/null +++ b/packages/backend-core/src/events/handlers/app.js @@ -0,0 +1,60 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.APP_CREATED, properties) +} + +exports.updated = () => { + const properties = {} + events.processEvent(Events.APP_UPDATED, properties) +} + +exports.deleted = () => { + const properties = {} + events.processEvent(Events.APP_DELETED, properties) +} + +exports.published = () => { + const properties = {} + events.processEvent(Events.APP_PUBLISHED, properties) +} + +exports.unpublished = () => { + const properties = {} + events.processEvent(Events.APP_UNPUBLISHED, properties) +} + +exports.fileImported = () => { + const properties = {} + events.processEvent(Events.APP_FILE_IMPORTED, properties) +} + +exports.templateImported = templateKey => { + const properties = { + templateKey, + } + events.processEvent(Events.APP_TEMPLATE_IMPORTED, properties) +} + +exports.versionUpdated = () => { + const properties = {} + events.processEvent(Events.APP_VERSION_UPDATED, properties) +} + +exports.versionReverted = () => { + const properties = {} + events.processEvent(Events.APP_VERSION_REVERTED, properties) +} + +exports.reverted = () => { + const properties = {} + events.processEvent(Events.APP_REVERTED, properties) +} + +// TODO +exports.exported = () => { + const properties = {} + events.processEvent(Events.APP_EXPORTED, properties) +} diff --git a/packages/backend-core/src/events/handlers/auth.js b/packages/backend-core/src/events/handlers/auth.js new file mode 100644 index 0000000000..eac957f2cb --- /dev/null +++ b/packages/backend-core/src/events/handlers/auth.js @@ -0,0 +1,40 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.login = () => { + const properties = {} + events.processEvent(Events.AUTH_LOGIN, properties) +} + +exports.logout = () => { + const properties = {} + events.processEvent(Events.AUTH_LOGOUT, properties) +} + +exports.SSOCreated = type => { + const properties = { + type, + } + events.processEvent(Events.AUTH_SSO_CREATED, properties) +} + +exports.SSOUpdated = type => { + const properties = { + type, + } + events.processEvent(Events.AUTH_SSO_UPDATED, properties) +} + +exports.SSOActivated = type => { + const properties = { + type, + } + events.processEvent(Events.AUTH_SSO_ACTIVATED, properties) +} + +exports.SSODeactivated = type => { + const properties = { + type, + } + events.processEvent(Events.AUTH_SSO_DEACTIVATED, properties) +} diff --git a/packages/backend-core/src/events/handlers/automation.js b/packages/backend-core/src/events/handlers/automation.js new file mode 100644 index 0000000000..72c2d73d56 --- /dev/null +++ b/packages/backend-core/src/events/handlers/automation.js @@ -0,0 +1,37 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_CREATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_DELETED, properties) +} + +// TODO +exports.tested = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_TESTED, properties) +} + +// TODO +exports.run = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_RUN, properties) +} + +// TODO +exports.stepCreated = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_STEP_CREATED, properties) +} + +// TODO +exports.stepDeleted = () => { + const properties = {} + events.processEvent(Events.AUTOMATION_STEP_DELETED, properties) +} diff --git a/packages/backend-core/src/events/handlers/datasource.js b/packages/backend-core/src/events/handlers/datasource.js new file mode 100644 index 0000000000..c946d19f51 --- /dev/null +++ b/packages/backend-core/src/events/handlers/datasource.js @@ -0,0 +1,19 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.DATASOURCE_CREATED, properties) +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.DATASOURCE_UPDATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.DATASOURCE_DELETED, properties) +} diff --git a/packages/backend-core/src/events/handlers/email.js b/packages/backend-core/src/events/handlers/email.js new file mode 100644 index 0000000000..189f82dec7 --- /dev/null +++ b/packages/backend-core/src/events/handlers/email.js @@ -0,0 +1,12 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.SMTPCreated = () => { + const properties = {} + events.processEvent(Events.EMAIL_SMTP_CREATED, properties) +} + +exports.SMTPUpdated = () => { + const properties = {} + events.processEvent(Events.EMAIL_SMTP_UPDATED, properties) +} diff --git a/packages/backend-core/src/events/handlers/index.js b/packages/backend-core/src/events/handlers/index.js new file mode 100644 index 0000000000..dc2fd4ea10 --- /dev/null +++ b/packages/backend-core/src/events/handlers/index.js @@ -0,0 +1,31 @@ +const app = require("./app") +const auth = require("./auth") +const automation = require("./automation") +const datasource = require("./datasource") +const email = require("./email") +const licensing = require("./licensing") +const layout = require("./layout") +const org = require("./org") +const query = require("./query") +const row = require("./screen") +const table = require("./table") +const serve = require("./serve") +const user = require("./user") +const view = require("./view") + +module.exports = { + app, + auth, + automation, + datasource, + email, + licensing, + layout, + org, + query, + row, + table, + serve, + user, + view, +} diff --git a/packages/backend-core/src/events/handlers/layout.js b/packages/backend-core/src/events/handlers/layout.js new file mode 100644 index 0000000000..682a0e6655 --- /dev/null +++ b/packages/backend-core/src/events/handlers/layout.js @@ -0,0 +1,16 @@ +const events = require("../events") +const { Events } = require("../constants") + +// LAYOUT + +// TODO +exports.created = () => { + const properties = {} + events.processEvent(Events.LAYOUT_CREATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.LAYOUT_DELETED, properties) +} diff --git a/packages/backend-core/src/events/handlers/licensing.js b/packages/backend-core/src/events/handlers/licensing.js new file mode 100644 index 0000000000..144a9abf78 --- /dev/null +++ b/packages/backend-core/src/events/handlers/licensing.js @@ -0,0 +1,10 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.quotaExceeded = (quotaName, value) => { + const properties = { + name: quotaName, + value, + } + events.processEvent(Events.LICENSING_QUOTA_EXCEEDED, properties) +} diff --git a/packages/backend-core/src/events/handlers/org.js b/packages/backend-core/src/events/handlers/org.js new file mode 100644 index 0000000000..f82ba3bae4 --- /dev/null +++ b/packages/backend-core/src/events/handlers/org.js @@ -0,0 +1,34 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.nameUpdated = () => { + const properties = {} + events.processEvent(Events.ORG_NAME_UPDATED, properties) +} + +exports.logoUpdated = () => { + const properties = {} + events.processEvent(Events.ORG_LOGO_UPDATED, properties) +} + +exports.platformURLUpdated = () => { + const properties = {} + events.processEvent(Events.ORG_PLATFORM_URL_UPDATED, properties) +} + +exports.versionChecked = version => { + const properties = { + version, + } + events.processEvent(Events.UPDATE_VERSION_CHECKED, properties) +} + +exports.analyticsOptOut = () => { + const properties = {} + events.processEvent(Events.ANALYTICS_OPT_OUT, properties) +} + +exports.npsSubmitted = () => { + const properties = {} + events.processEvent(Events.NPS_SUBMITTED, properties) +} diff --git a/packages/backend-core/src/events/handlers/query.js b/packages/backend-core/src/events/handlers/query.js new file mode 100644 index 0000000000..aa303bd06f --- /dev/null +++ b/packages/backend-core/src/events/handlers/query.js @@ -0,0 +1,37 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.QUERY_CREATED, properties) +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.QUERY_UPDATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.QUERY_DELETED, properties) +} + +// TODO +exports.imported = () => { + const properties = {} + events.processEvent(Events.QUERY_IMPORTED, properties) +} + +// TODO +exports.run = () => { + const properties = {} + events.processEvent(Events.QUERY_RUN, properties) +} + +// TODO +exports.previewed = () => { + const properties = {} + events.processEvent(Events.QUERY_PREVIEWED, properties) +} diff --git a/packages/backend-core/src/events/handlers/role.js b/packages/backend-core/src/events/handlers/role.js new file mode 100644 index 0000000000..16b342f214 --- /dev/null +++ b/packages/backend-core/src/events/handlers/role.js @@ -0,0 +1,19 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.ROLE_CREATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.ROLE_DELETED, properties) +} + +// TODO +exports.assigned = () => { + const properties = {} + events.processEvent(Events.ROLE_ASSIGNED, properties) +} diff --git a/packages/backend-core/src/events/handlers/row.js b/packages/backend-core/src/events/handlers/row.js new file mode 100644 index 0000000000..3f5b30839a --- /dev/null +++ b/packages/backend-core/src/events/handlers/row.js @@ -0,0 +1,26 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.ROW_CREATED, properties) +} + +// TODO +exports.imported = () => { + const properties = {} + events.processEvent(Events.ROW_IMPORTED, properties) + exports.rowCreated() +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.ROW_UPDATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.ROW_DELETED, properties) +} diff --git a/packages/backend-core/src/events/handlers/screen.js b/packages/backend-core/src/events/handlers/screen.js new file mode 100644 index 0000000000..53bc2b4fc7 --- /dev/null +++ b/packages/backend-core/src/events/handlers/screen.js @@ -0,0 +1,14 @@ +const events = require("../events") +const { Events } = require("../constants") + +// TODO +exports.created = () => { + const properties = {} + events.processEvent(Events.SCREEN_CREATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.SCREEN_DELETED, properties) +} diff --git a/packages/backend-core/src/events/handlers/serve.js b/packages/backend-core/src/events/handlers/serve.js new file mode 100644 index 0000000000..29c67d00ab --- /dev/null +++ b/packages/backend-core/src/events/handlers/serve.js @@ -0,0 +1,14 @@ +const events = require("../events") +const { Events } = require("../constants") + +// TODO +exports.builderServed = () => { + const properties = {} + events.processEvent(Events.BUILDER_SERVED, properties) +} + +// TODO +exports.clientServed = () => { + const properties = {} + events.processEvent(Events.CLIENT_SERVED, properties) +} diff --git a/packages/backend-core/src/events/handlers/table.js b/packages/backend-core/src/events/handlers/table.js new file mode 100644 index 0000000000..b6ddb44fd1 --- /dev/null +++ b/packages/backend-core/src/events/handlers/table.js @@ -0,0 +1,37 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.TABLE_CREATED, properties) +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.TABLE_UPDATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.TABLE_DELETED, properties) +} + +// TODO +exports.exported = () => { + const properties = {} + events.processEvent(Events.TABLE_EXPORTED, properties) +} + +// TODO +exports.imported = () => { + const properties = {} + events.processEvent(Events.TABLE_IMPORTED, properties) +} + +// TODO +exports.permissionUpdated = () => { + const properties = {} + events.processEvent(Events.TABLE_PERMISSION_UPDATED, properties) +} diff --git a/packages/backend-core/src/events/handlers/user.js b/packages/backend-core/src/events/handlers/user.js new file mode 100644 index 0000000000..7d1bc592e8 --- /dev/null +++ b/packages/backend-core/src/events/handlers/user.js @@ -0,0 +1,85 @@ +const events = require("../events") +const { Events } = require("../constants") + +// TODO +exports.created = () => { + const properties = {} + events.processEvent(Events.USER_CREATED, properties) +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.USER_UPDATED, properties) +} + +exports.deleted = () => { + const properties = {} + events.processEvent(Events.USER_DELETED, properties) +} + +// TODO +exports.passwordForceReset = () => { + const properties = {} + events.processEvent(Events.USER_PASSWORD_FORCE_RESET, properties) +} + +// PERMISSIONS + +// TODO +exports.permissionAdminAssigned = () => { + const properties = {} + events.processEvent(Events.USER_PERMISSION_ADMIN_ASSIGNED, properties) +} + +// TODO +exports.permissionAdminRemoved = () => { + const properties = {} + events.processEvent(Events.USER_PERMISSION_ADMIN_REMOVED, properties) +} + +// TODO +exports.permissionBuilderAssigned = () => { + const properties = {} + events.processEvent(Events.USER_PERMISSION_BUILDER_ASSIGNED, properties) +} + +// TODO +exports.permissionBuilderRemoved = () => { + const properties = {} + events.processEvent(Events.USER_PERMISSION_BUILDER_REMOVED, properties) +} + +// INVITE + +exports.invited = () => { + const properties = {} + events.processEvent(Events.USER_INVITED, properties) +} + +exports.inviteAccepted = () => { + const properties = {} + events.processEvent(Events.USER_INVITED_ACCEPTED, properties) +} + +// SELF + +exports.selfUpdated = () => { + const properties = {} + events.processEvent(Events.USER_SELF_UPDATED, properties) +} + +exports.selfPasswordUpdated = () => { + const properties = {} + events.processEvent(Events.USER_SELF_PASSWORD_UPDATED, properties) +} + +exports.passwordResetRequested = () => { + const properties = {} + events.processEvent(Events.USER_PASSWORD_RESET_REQUESTED, properties) +} + +exports.passwordReset = () => { + const properties = {} + events.processEvent(Events.USER_PASSWORD_RESET, properties) +} diff --git a/packages/backend-core/src/events/handlers/view.js b/packages/backend-core/src/events/handlers/view.js new file mode 100644 index 0000000000..551960fcb0 --- /dev/null +++ b/packages/backend-core/src/events/handlers/view.js @@ -0,0 +1,49 @@ +const events = require("../events") +const { Events } = require("../constants") + +exports.created = () => { + const properties = {} + events.processEvent(Events.VIEW_CREATED, properties) +} + +// TODO +exports.updated = () => { + const properties = {} + events.processEvent(Events.VIEW_UPDATED, properties) +} + +// TODO +exports.deleted = () => { + const properties = {} + events.processEvent(Events.VIEW_DELETED, properties) +} + +// TODO +exports.exported = () => { + const properties = {} + events.processEvent(Events.VIEW_EXPORTED, properties) +} + +// TODO +exports.filterCreated = () => { + const properties = {} + events.processEvent(Events.VIEW_FILTER_CREATED, properties) +} + +// TODO +exports.filterDeleted = () => { + const properties = {} + events.processEvent(Events.VIEW_FILTER_DELETED, properties) +} + +// TODO +exports.calculationCreated = () => { + const properties = {} + events.processEvent(Events.VIEW_CALCULATION_CREATED, properties) +} + +// TODO +exports.calculationDeleted = () => { + const properties = {} + events.processEvent(Events.VIEW_CALCULATION_DELETED, properties) +} diff --git a/packages/backend-core/src/events/index.js b/packages/backend-core/src/events/index.js index e91cc25703..024194081b 100644 --- a/packages/backend-core/src/events/index.js +++ b/packages/backend-core/src/events/index.js @@ -1,2 +1,5 @@ -const events = require("./events") -module.exports = events +const handlers = require("./handlers") + +module.exports = { + ...handlers, +} diff --git a/packages/backend-core/src/index.js b/packages/backend-core/src/index.js index 2e5249a653..8450ba58d6 100644 --- a/packages/backend-core/src/index.js +++ b/packages/backend-core/src/index.js @@ -21,4 +21,5 @@ module.exports = { tenancy: require("./tenancy"), featureFlags: require("./featureFlags"), events: require("./events"), + analytics: require("./analytics"), } diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 28e07878d9..191b69a702 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -51,7 +51,7 @@ const { } = require("@budibase/backend-core/context") import { getUniqueRows } from "../../utilities/usageQuota/rows" import { quotas } from "@budibase/pro" -import { errors } from "@budibase/backend-core" +import { errors, events } from "@budibase/backend-core" const URL_REGEX_SLASH = /\/|\\/g @@ -291,7 +291,33 @@ const performAppCreate = async (ctx: any) => { return newApplication } +const creationEvents = (request: any) => { + let creationFns = [] + + const body = request.body + if (body.useTemplate === "true") { + // from template + if (body.templateKey) { + creationFns.push(() => events.app.templateImported(body.templateKey)) + } + // from file + else if (request.files?.templateFile) { + creationFns.push(events.app.fileImported) + } + // unknown + else { + console.error("Could not determine template creation event") + } + } + creationFns.push(events.app.created) + + for (let fn of creationFns) { + fn() + } +} + const appPostCreate = async (ctx: any, appId: string) => { + creationEvents(ctx.request) // app import & template creation if (ctx.request.body.useTemplate === "true") { const rows = await getUniqueRows([appId]) @@ -336,6 +362,7 @@ export const update = async (ctx: any) => { } const data = await updateAppPackage(ctx.request.body, ctx.params.appId) + events.app.updated() ctx.status = 200 ctx.body = data } @@ -358,6 +385,7 @@ export const updateClient = async (ctx: any) => { revertableVersion: currentVersion, } const data = await updateAppPackage(appPackageUpdates, ctx.params.appId) + events.app.versionUpdated() ctx.status = 200 ctx.body = data } @@ -381,6 +409,7 @@ export const revertClient = async (ctx: any) => { revertableVersion: null, } const data = await updateAppPackage(appPackageUpdates, ctx.params.appId) + events.app.versionReverted() ctx.status = 200 ctx.body = data } @@ -391,8 +420,10 @@ const destroyApp = async (ctx: any) => { const result = await db.destroy() if (ctx.query?.unpublish) { await quotas.removePublishedApp() + events.app.unpublished() } else { await quotas.removeApp() + events.app.deleted() } /* istanbul ignore next */ if (!env.isTest() && !ctx.query.unpublish) { diff --git a/packages/server/src/api/controllers/backup.js b/packages/server/src/api/controllers/backup.js index daaa59b341..193f4139c5 100644 --- a/packages/server/src/api/controllers/backup.js +++ b/packages/server/src/api/controllers/backup.js @@ -1,4 +1,5 @@ const { streamBackup } = require("../../utilities/fileSystem") +const { events } = require("@budibase/backend-core") exports.exportAppDump = async function (ctx) { const { appId } = ctx.query @@ -6,4 +7,5 @@ exports.exportAppDump = async function (ctx) { const backupIdentifier = `${appName}-export-${new Date().getTime()}.txt` ctx.attachment(backupIdentifier) ctx.body = await streamBackup(appId) + events.app.exported() } diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 663d4297fb..44de78fcc8 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -13,6 +13,7 @@ import { getProdAppDB, } from "@budibase/backend-core/context" import { quotas } from "@budibase/pro" +import { events } from "@budibase/backend-core" // the max time we can wait for an invalidation to complete before considering it failed const MAX_PENDING_TIME_MS = 30 * 60000 @@ -185,6 +186,7 @@ const _deployApp = async function (ctx: any) { await deployApp(deployment) } + events.app.published() ctx.body = deployment } diff --git a/packages/server/src/api/controllers/dev.js b/packages/server/src/api/controllers/dev.js index 54f554e358..208d91c699 100644 --- a/packages/server/src/api/controllers/dev.js +++ b/packages/server/src/api/controllers/dev.js @@ -7,6 +7,7 @@ const { Replication, getProdAppID } = require("@budibase/backend-core/db") const { DocumentTypes } = require("../../db/utils") const { app: appCache } = require("@budibase/backend-core/cache") const { getProdAppDB, getAppDB } = require("@budibase/backend-core/context") +const { events } = require("@budibase/backend-core") async function redirect(ctx, method, path = "global") { const { devPath } = ctx.params @@ -101,7 +102,10 @@ exports.revert = async ctx => { target: appId, }) - await replication.rollback() + if (!env.isTest()) { + // in-memory db stalls on rollback + await replication.rollback() + } // update appID in reverted app to be dev version again const db = getAppDB() const appDoc = await db.get(DocumentTypes.APP_METADATA) @@ -112,13 +116,16 @@ exports.revert = async ctx => { ctx.body = { message: "Reverted changes successfully.", } + events.app.reverted() } catch (err) { ctx.throw(400, `Unable to revert. ${err}`) } } exports.getBudibaseVersion = async ctx => { + const version = require("../../../package.json").version ctx.body = { - version: require("../../../package.json").version, + version, } + events.org.versionChecked(version) } diff --git a/packages/server/src/api/routes/tests/application.spec.js b/packages/server/src/api/routes/tests/application.spec.js index d2273a31b8..6f215165fe 100644 --- a/packages/server/src/api/routes/tests/application.spec.js +++ b/packages/server/src/api/routes/tests/application.spec.js @@ -28,17 +28,49 @@ describe("/applications", () => { beforeEach(async () => { await clearAllApps() await config.init() + jest.clearAllMocks() }) describe("create", () => { - it("returns a success message when the application is successfully created", async () => { + it("creates empty app", async () => { const res = await request .post("/api/applications") - .send({ name: "My App" }) + .field("name", "My App") .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) expect(res.body._id).toBeDefined() + expect(config.getEvents().app.created.mock.calls.length).toBe(1) + }) + + it("creates app from template", async () => { + const res = await request + .post("/api/applications") + .field("name", "My App") + .field("useTemplate", "true") + .field("templateKey", "test") + .field("templateString", "{}") // override the file download + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body._id).toBeDefined() + expect(config.getEvents().app.created.mock.calls.length).toBe(1) + expect(config.getEvents().app.templateImported.mock.calls.length).toBe(1) + }) + + + it("creates app from file", async () => { + const res = await request + .post("/api/applications") + .field("name", "My App") + .field("useTemplate", "true") + .set(config.defaultHeaders()) + .attach('templateFile', 'src/api/routes/tests/data/export.txt') + .expect("Content-Type", /json/) + .expect(200) + expect(res.body._id).toBeDefined() + expect(config.getEvents().app.created.mock.calls.length).toBe(1) + expect(config.getEvents().app.fileImported.mock.calls.length).toBe(1) }) it("should apply authorization to endpoint", async () => { @@ -102,6 +134,31 @@ describe("/applications", () => { .expect("Content-Type", /json/) .expect(200) expect(res.body.rev).toBeDefined() + expect(config.getEvents().app.updated.mock.calls.length).toBe(1) + }) + }) + + describe("delete", () => { + it("should delete app", async () => { + await config.createApp("to-delete") + const appId = config.getAppId() + await request + .delete(`/api/applications/${appId}`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(config.getEvents().app.deleted.mock.calls.length).toBe(1) + }) + + it("should unpublish app", async () => { + await config.createApp("to-unpublish") + const appId = config.getProdAppId() + await request + .delete(`/api/applications/${appId}?unpublish=true`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(config.getEvents().app.unpublished.mock.calls.length).toBe(1) }) }) @@ -113,6 +170,7 @@ describe("/applications", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) + expect(config.getEvents().app.versionUpdated.mock.calls.length).toBe(1) }) it("should be able to revert the app client library version", async () => { // We need to first update the version so that we can then revert @@ -126,6 +184,7 @@ describe("/applications", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) + expect(config.getEvents().app.versionReverted.mock.calls.length).toBe(1) }) }) diff --git a/packages/server/src/api/routes/tests/backup.spec.js b/packages/server/src/api/routes/tests/backup.spec.js index 78c0ee9268..a69cc9f31b 100644 --- a/packages/server/src/api/routes/tests/backup.spec.js +++ b/packages/server/src/api/routes/tests/backup.spec.js @@ -21,6 +21,7 @@ describe("/backups", () => { .expect(200) expect(res.text).toBeDefined() expect(res.text.includes(`"db_name":"${config.getAppId()}"`)).toEqual(true) + expect(config.getEvents().app.exported.mock.calls.length).toBe(1) }) it("should apply authorization to endpoint", async () => { diff --git a/packages/server/src/api/routes/tests/data/export.txt b/packages/server/src/api/routes/tests/data/export.txt new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/server/src/api/routes/tests/data/export.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/server/src/api/routes/tests/deployment.spec.js b/packages/server/src/api/routes/tests/deployment.spec.js new file mode 100644 index 0000000000..221a2164e2 --- /dev/null +++ b/packages/server/src/api/routes/tests/deployment.spec.js @@ -0,0 +1,24 @@ +const setup = require("./utilities") + +describe("/deployments", () => { + let request = setup.getRequest() + let config = setup.getConfig() + + afterAll(setup.afterAll) + + beforeEach(async () => { + await config.init() + jest.clearAllMocks() + }) + + describe("deploy", () => { + it("should deploy the application", async () => { + await request + .post(`/api/deploy`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(config.getEvents().app.published.mock.calls.length).toBe(1) + }) + }) +}) \ No newline at end of file diff --git a/packages/server/src/api/routes/tests/dev.spec.js b/packages/server/src/api/routes/tests/dev.spec.js new file mode 100644 index 0000000000..63e503bfb2 --- /dev/null +++ b/packages/server/src/api/routes/tests/dev.spec.js @@ -0,0 +1,24 @@ +const setup = require("./utilities") + +describe("/dev", () => { + let request = setup.getRequest() + let config = setup.getConfig() + + afterAll(setup.afterAll) + + beforeEach(async () => { + await config.init() + jest.clearAllMocks() + }) + + describe("revert", () => { + it("should revert the application", async () => { + await request + .post(`/api/dev/${config.getAppId()}/revert`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(config.getEvents().app.reverted.mock.calls.length).toBe(1) + }) + }) +}) \ No newline at end of file diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index 5d240d02d6..f25c76793f 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -25,6 +25,7 @@ const newid = require("../../db/newid") const context = require("@budibase/backend-core/context") const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db") const { encrypt } = require("@budibase/backend-core/encryption") +const { events } = require("./mockEvents") const GLOBAL_USER_ID = "us_uuid1" const EMAIL = "babs@babs.com" @@ -55,6 +56,14 @@ class TestConfiguration { return this.appId } + getProdAppId() { + return this.prodAppId + } + + getEvents() { + return events + } + async _req(config, params, controlFunc) { const request = {} // fake cookies, we don't need them diff --git a/packages/server/src/tests/utilities/mockEvents.js b/packages/server/src/tests/utilities/mockEvents.js new file mode 100644 index 0000000000..4860024240 --- /dev/null +++ b/packages/server/src/tests/utilities/mockEvents.js @@ -0,0 +1,22 @@ +const core = require("@budibase/backend-core") + +const events = { + app: { + created: jest.fn(), + updated: jest.fn(), + deleted: jest.fn(), + published: jest.fn(), + unpublished: jest.fn(), + templateImported: jest.fn(), + fileImported: jest.fn(), + versionUpdated: jest.fn(), + versionReverted: jest.fn(), + reverted: jest.fn(), + exported: jest.fn(), + }, +} + +core.events = events +module.exports = { + events, +}