diff --git a/redisinsight/api/src/modules/core/models/server-provider.interface.ts b/redisinsight/api/src/modules/core/models/server-provider.interface.ts index 71d1e4bc1f..fe231a125f 100644 --- a/redisinsight/api/src/modules/core/models/server-provider.interface.ts +++ b/redisinsight/api/src/modules/core/models/server-provider.interface.ts @@ -6,6 +6,14 @@ export enum BuildType { DockerOnPremise = 'DOCKER_ON_PREMISE', } +export enum AppType { + RedisStackWeb = 'REDIS_STACK_WEB', + RedisStackApp = 'REDIS_STACK_ELECTRON', + Electron = 'ELECTRON', + Docker = 'DOCKER', + Unknown = 'UNKNOWN', +} + export interface IServerProvider { getInfo(): Promise; } diff --git a/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.spec.ts b/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.spec.ts index 26ff9a3c40..d947581546 100644 --- a/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.spec.ts +++ b/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.spec.ts @@ -94,7 +94,7 @@ describe('ServerOnPremiseService', () => { expect(eventEmitter.emit).toHaveBeenNthCalledWith( 1, AppAnalyticsEvents.Initialize, - { anonymousId: mockServerEntity.id, sessionId }, + { anonymousId: mockServerEntity.id, sessionId, appType: SERVER_CONFIG.buildType }, ); expect(eventEmitter.emit).toHaveBeenNthCalledWith( 2, @@ -113,7 +113,7 @@ describe('ServerOnPremiseService', () => { expect(eventEmitter.emit).toHaveBeenNthCalledWith( 1, AppAnalyticsEvents.Initialize, - { anonymousId: mockServerEntity.id, sessionId }, + { anonymousId: mockServerEntity.id, sessionId, appType: SERVER_CONFIG.buildType }, ); expect(eventEmitter.emit).toHaveBeenNthCalledWith( 2, @@ -140,6 +140,7 @@ describe('ServerOnPremiseService', () => { appVersion: SERVER_CONFIG.appVersion, osPlatform: process.platform, buildType: SERVER_CONFIG.buildType, + appType: SERVER_CONFIG.buildType, encryptionStrategies: [ EncryptionStrategy.PLAIN, EncryptionStrategy.KEYTAR, diff --git a/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.ts b/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.ts index 0a7e135106..c48fb796a9 100644 --- a/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.ts +++ b/redisinsight/api/src/modules/core/providers/server-on-premise/server-on-premise.service.ts @@ -1,16 +1,11 @@ -import { - Injectable, - InternalServerErrorException, - Logger, - OnApplicationBootstrap, -} from '@nestjs/common'; +import { Injectable, InternalServerErrorException, Logger, OnApplicationBootstrap } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import config from 'src/utils/config'; import { AppAnalyticsEvents } from 'src/constants/app-events'; import { TelemetryEvents } from 'src/constants/telemetry-events'; import { GetServerInfoResponse } from 'src/dto/server.dto'; import { ServerRepository } from 'src/modules/core/repositories/server.repository'; -import { IServerProvider } from 'src/modules/core/models/server-provider.interface'; +import { AppType, BuildType, IServerProvider } from 'src/modules/core/models/server-provider.interface'; import { ServerInfoNotFoundException } from 'src/constants/exceptions'; import { EncryptionService } from 'src/modules/core/encryption/encryption.service'; @@ -49,7 +44,11 @@ implements OnApplicationBootstrap, IServerProvider { // Create default server info on first application launch serverInfo = this.repository.create({}); await this.repository.save(serverInfo); - this.eventEmitter.emit(AppAnalyticsEvents.Initialize, { anonymousId: serverInfo.id, sessionId: this.sessionId }); + this.eventEmitter.emit(AppAnalyticsEvents.Initialize, { + anonymousId: serverInfo.id, + sessionId: this.sessionId, + appType: this.getAppType(SERVER_CONFIG.buildType), + }); this.eventEmitter.emit(AppAnalyticsEvents.Track, { event: TelemetryEvents.ApplicationFirstStart, eventData: { @@ -61,7 +60,11 @@ implements OnApplicationBootstrap, IServerProvider { }); } else { this.logger.log('Application started.'); - this.eventEmitter.emit(AppAnalyticsEvents.Initialize, { anonymousId: serverInfo.id, sessionId: this.sessionId }); + this.eventEmitter.emit(AppAnalyticsEvents.Initialize, { + anonymousId: serverInfo.id, + sessionId: this.sessionId, + appType: this.getAppType(SERVER_CONFIG.buildType), + }); this.eventEmitter.emit(AppAnalyticsEvents.Track, { event: TelemetryEvents.ApplicationStarted, eventData: { @@ -90,6 +93,7 @@ implements OnApplicationBootstrap, IServerProvider { appVersion: SERVER_CONFIG.appVersion, osPlatform: process.platform, buildType: SERVER_CONFIG.buildType, + appType: this.getAppType(SERVER_CONFIG.buildType), encryptionStrategies: await this.encryptionService.getAvailableEncryptionStrategies(), fixedDatabaseId: REDIS_STACK_CONFIG?.id, }; @@ -100,4 +104,17 @@ implements OnApplicationBootstrap, IServerProvider { throw new InternalServerErrorException(); } } + + getAppType(buildType: string): AppType { + switch (buildType) { + case BuildType.DockerOnPremise: + return AppType.Docker; + case BuildType.Electron: + return AppType.Electron; + case BuildType.RedisStack: + return AppType.RedisStackWeb; + default: + return AppType.Unknown; + } + } } diff --git a/redisinsight/api/src/modules/core/services/analytics/analytics.service.spec.ts b/redisinsight/api/src/modules/core/services/analytics/analytics.service.spec.ts index 1d5bf0986f..dfb018e7ab 100644 --- a/redisinsight/api/src/modules/core/services/analytics/analytics.service.spec.ts +++ b/redisinsight/api/src/modules/core/services/analytics/analytics.service.spec.ts @@ -6,6 +6,7 @@ import { AnalyticsService, NON_TRACKING_ANONYMOUS_ID, } from './analytics.service'; +import { AppType } from 'src/modules/core/models/server-provider.interface'; let mockAnalyticsTrack; jest.mock( @@ -59,7 +60,7 @@ describe('AnalyticsService', () => { describe('initialize', () => { it('should set anonymousId', () => { - service.initialize({ anonymousId: mockAnonymousId, sessionId }); + service.initialize({ anonymousId: mockAnonymousId, sessionId, appType: AppType.Electron }); const anonymousId = service.getAnonymousId(); @@ -70,7 +71,7 @@ describe('AnalyticsService', () => { describe('sendEvent', () => { beforeEach(() => { mockAnalyticsTrack = jest.fn(); - service.initialize({ anonymousId: mockAnonymousId, sessionId }); + service.initialize({ anonymousId: mockAnonymousId, sessionId, appType: AppType.Electron }); }); it('should send event with anonymousId if permission are granted', async () => { settingsService.getSettings = jest @@ -87,7 +88,9 @@ describe('AnalyticsService', () => { anonymousId: mockAnonymousId, integrations: { Amplitude: { session_id: sessionId } }, event: TelemetryEvents.ApplicationStarted, - properties: {}, + properties: { + buildType: AppType.Electron, + }, }); }); it('should not send event if permission are not granted', async () => { @@ -118,7 +121,9 @@ describe('AnalyticsService', () => { anonymousId: mockAnonymousId, integrations: { Amplitude: { session_id: sessionId } }, event: TelemetryEvents.ApplicationStarted, - properties: {}, + properties: { + buildType: AppType.Electron, + }, }); }); }); diff --git a/redisinsight/api/src/modules/core/services/analytics/analytics.service.ts b/redisinsight/api/src/modules/core/services/analytics/analytics.service.ts index 98c48207a6..bf4f747fc4 100644 --- a/redisinsight/api/src/modules/core/services/analytics/analytics.service.ts +++ b/redisinsight/api/src/modules/core/services/analytics/analytics.service.ts @@ -18,6 +18,7 @@ export interface ITelemetryEvent { export interface ITelemetryInitEvent { anonymousId: string; sessionId: number; + appType: string; } @Injectable() @@ -26,6 +27,8 @@ export class AnalyticsService { private sessionId: number = -1; + private appType: string = 'unknown'; + private analytics; constructor( @@ -39,9 +42,10 @@ export class AnalyticsService { @OnEvent(AppAnalyticsEvents.Initialize) public initialize(payload: ITelemetryInitEvent) { - const { anonymousId, sessionId } = payload; + const { anonymousId, sessionId, appType } = payload; this.sessionId = sessionId; this.anonymousId = anonymousId; + this.appType = appType; this.analytics = new Analytics(ANALYTICS_CONFIG.writeKey); } @@ -68,6 +72,7 @@ export class AnalyticsService { event, properties: { ...eventData, + buildType: this.appType, }, }); } diff --git a/redisinsight/api/test/api/info/GET-info.test.ts b/redisinsight/api/test/api/info/GET-info.test.ts index ab16f69986..af557dfdf6 100644 --- a/redisinsight/api/test/api/info/GET-info.test.ts +++ b/redisinsight/api/test/api/info/GET-info.test.ts @@ -17,6 +17,7 @@ const responseSchema = Joi.object().keys({ appVersion: Joi.string().required(), osPlatform: Joi.string().required(), buildType: Joi.string().valid('ELECTRON', 'DOCKER_ON_PREMISE', 'REDIS_STACK').required(), + appType: Joi.string().valid('ELECTRON', 'DOCKER', 'REDIS_STACK_WEB', 'UNKNOWN').required(), encryptionStrategies: Joi.array().items(Joi.string()), sessionId: Joi.number().required(), }).required();