Browse Source

feat: remove analytics scope from other services in favor of a separate service

Karol Sójko 2 years ago
parent
commit
ff1d5db12c
92 changed files with 95 additions and 1788 deletions
  1. 0 1
      .pnp.cjs
  2. 1 41
      packages/analytics/bin/report.ts
  3. 2 5
      packages/analytics/package.json
  4. 12 0
      packages/analytics/src/Bootstrap/Container.ts
  5. 1 0
      packages/analytics/src/Bootstrap/Types.ts
  6. 0 8
      packages/analytics/src/Domain/Analytics/AnalyticsActivity.ts
  7. 2 32
      packages/analytics/src/Domain/Event/DomainEventFactory.spec.ts
  8. 3 1
      packages/analytics/src/Domain/Handler/RefundProcessedEventHandler.spec.ts
  9. 3 1
      packages/analytics/src/Domain/Handler/RefundProcessedEventHandler.ts
  10. 0 3
      packages/analytics/src/Domain/Statistics/StatisticsMeasure.ts
  11. 0 7
      packages/analytics/src/Domain/index.ts
  12. 37 39
      packages/analytics/src/Infra/Redis/RedisAnalyticsStore.spec.ts
  13. 2 1
      packages/analytics/src/Infra/Redis/RedisStatisticsStore.spec.ts
  14. 2 1
      packages/analytics/src/Infra/Redis/RedisStatisticsStore.ts
  15. 0 2
      packages/analytics/src/Infra/index.ts
  16. 0 2
      packages/analytics/src/index.ts
  17. 0 1
      packages/api-gateway/package.json
  18. 0 17
      packages/api-gateway/src/Bootstrap/Container.ts
  19. 0 4
      packages/api-gateway/src/Bootstrap/Types.ts
  20. 0 13
      packages/api-gateway/src/Controller/AuthMiddleware.ts
  21. 1 1
      packages/api-gateway/src/Controller/LegacyController.ts
  22. 0 31
      packages/api-gateway/src/Controller/StatisticsMiddleware.ts
  23. 1 1
      packages/api-gateway/src/Controller/v1/ActionsController.ts
  24. 1 1
      packages/api-gateway/src/Controller/v1/FilesController.ts
  25. 1 1
      packages/api-gateway/src/Controller/v1/InvoicesController.ts
  26. 1 1
      packages/api-gateway/src/Controller/v1/ItemsController.ts
  27. 1 1
      packages/api-gateway/src/Controller/v1/OfflineController.ts
  28. 1 1
      packages/api-gateway/src/Controller/v1/PaymentsController.ts
  29. 1 1
      packages/api-gateway/src/Controller/v1/RevisionsController.ts
  30. 1 1
      packages/api-gateway/src/Controller/v1/SessionsController.ts
  31. 1 1
      packages/api-gateway/src/Controller/v1/SubscriptionInvitesController.ts
  32. 1 1
      packages/api-gateway/src/Controller/v1/TokensController.ts
  33. 1 1
      packages/api-gateway/src/Controller/v1/UsersController.ts
  34. 1 1
      packages/api-gateway/src/Controller/v2/ActionsControllerV2.ts
  35. 1 1
      packages/api-gateway/src/Controller/v2/PaymentsControllerV2.ts
  36. 0 3
      packages/auth/.env.sample
  37. 1 66
      packages/auth/bin/backup.ts
  38. 1 29
      packages/auth/bin/user_email_backup.ts
  39. 0 1
      packages/auth/package.json
  40. 0 40
      packages/auth/src/Bootstrap/Container.ts
  41. 0 2
      packages/auth/src/Bootstrap/DataSource.ts
  42. 0 10
      packages/auth/src/Bootstrap/Types.ts
  43. 0 7
      packages/auth/src/Controller/SubscriptionTokensController.spec.ts
  44. 0 5
      packages/auth/src/Controller/SubscriptionTokensController.ts
  45. 0 19
      packages/auth/src/Domain/Analytics/AnalyticsEntity.ts
  46. 0 7
      packages/auth/src/Domain/Analytics/AnalyticsEntityRepositoryInterface.ts
  47. 0 24
      packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.spec.ts
  48. 0 28
      packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.ts
  49. 0 51
      packages/auth/src/Domain/Handler/PaymentFailedEventHandler.spec.ts
  50. 0 30
      packages/auth/src/Domain/Handler/PaymentFailedEventHandler.ts
  51. 0 90
      packages/auth/src/Domain/Handler/PaymentSuccessEventHandler.spec.ts
  52. 0 102
      packages/auth/src/Domain/Handler/PaymentSuccessEventHandler.ts
  53. 1 65
      packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.spec.ts
  54. 1 61
      packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.ts
  55. 0 17
      packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.spec.ts
  56. 0 26
      packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.ts
  57. 0 57
      packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts
  58. 0 57
      packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts
  59. 0 78
      packages/auth/src/Domain/Handler/SubscriptionReactivatedEventHandler.spec.ts
  60. 0 34
      packages/auth/src/Domain/Handler/SubscriptionReactivatedEventHandler.ts
  61. 0 47
      packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.spec.ts
  62. 1 47
      packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.ts
  63. 0 13
      packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.spec.ts
  64. 0 16
      packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.ts
  65. 2 26
      packages/auth/src/Domain/Handler/UserRegisteredEventHandler.spec.ts
  66. 0 11
      packages/auth/src/Domain/Handler/UserRegisteredEventHandler.ts
  67. 2 44
      packages/auth/src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken.spec.ts
  68. 0 8
      packages/auth/src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken.ts
  69. 0 37
      packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId.spec.ts
  70. 0 25
      packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId.ts
  71. 0 5
      packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsIdDTO.ts
  72. 0 3
      packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsIdResponse.ts
  73. 1 18
      packages/auth/src/Domain/UseCase/Register.spec.ts
  74. 0 7
      packages/auth/src/Domain/UseCase/Register.ts
  75. 1 12
      packages/auth/src/Domain/User/User.ts
  76. 0 42
      packages/auth/src/Infra/MySQL/MySQLAnalyticsEntityRepository.spec.ts
  77. 0 26
      packages/auth/src/Infra/MySQL/MySQLAnalyticsEntityRepository.ts
  78. 0 1
      packages/security/src/Domain/Token/CrossServiceTokenData.ts
  79. 0 1
      packages/syncing-server/package.json
  80. 0 14
      packages/syncing-server/src/Bootstrap/Container.ts
  81. 0 2
      packages/syncing-server/src/Bootstrap/Types.ts
  82. 0 5
      packages/syncing-server/src/Controller/AuthMiddleware.spec.ts
  83. 0 1
      packages/syncing-server/src/Controller/AuthMiddleware.ts
  84. 0 6
      packages/syncing-server/src/Controller/ItemsController.spec.ts
  85. 0 2
      packages/syncing-server/src/Controller/ItemsController.ts
  86. 1 101
      packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrity.spec.ts
  87. 2 56
      packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrity.ts
  88. 0 1
      packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrityDTO.ts
  89. 1 58
      packages/syncing-server/src/Domain/UseCase/SyncItems.spec.ts
  90. 1 18
      packages/syncing-server/src/Domain/UseCase/SyncItems.ts
  91. 0 1
      packages/syncing-server/src/Domain/UseCase/SyncItemsDTO.ts
  92. 0 1
      yarn.lock

+ 0 - 1
.pnp.cjs

@@ -2651,7 +2651,6 @@ const RAW_RUNTIME_STATE =
           ["@standardnotes/auth-server", "workspace:packages/auth"],\
           ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
           ["@sentry/node", "npm:7.5.0"],\
-          ["@standardnotes/analytics", "workspace:packages/analytics"],\
           ["@standardnotes/api", "npm:1.19.0"],\
           ["@standardnotes/common", "workspace:packages/common"],\
           ["@standardnotes/domain-events", "workspace:packages/domain-events"],\

+ 1 - 41
packages/analytics/bin/report.ts

@@ -34,8 +34,6 @@ const requestReport = async (
   }> = []
 
   const thirtyDaysAnalyticsNames = [
-    AnalyticsActivity.GeneralActivity,
-    AnalyticsActivity.EditingItems,
     AnalyticsActivity.SubscriptionPurchased,
     AnalyticsActivity.Register,
     AnalyticsActivity.SubscriptionRenewed,
@@ -80,9 +78,6 @@ const requestReport = async (
   }> = []
   const yesterdayActivityNames = [
     AnalyticsActivity.LimitedDiscountOfferPurchased,
-    AnalyticsActivity.GeneralActivity,
-    AnalyticsActivity.GeneralActivityFreeUsers,
-    AnalyticsActivity.GeneralActivityPaidUsers,
     AnalyticsActivity.PaymentFailed,
     AnalyticsActivity.PaymentSuccess,
     AnalyticsActivity.NewCustomersChurn,
@@ -116,9 +111,6 @@ const requestReport = async (
     StatisticsMeasure.SubscriptionLength,
     StatisticsMeasure.RegistrationToSubscriptionTime,
     StatisticsMeasure.RemainingSubscriptionTimePercentage,
-    StatisticsMeasure.NotesCountFreeUsers,
-    StatisticsMeasure.NotesCountPaidUsers,
-    StatisticsMeasure.FilesCount,
     StatisticsMeasure.NewCustomers,
     StatisticsMeasure.TotalCustomers,
   ]
@@ -141,29 +133,6 @@ const requestReport = async (
     }
   }
 
-  const periodKeys = periodKeyGenerator.getDiscretePeriodKeys(Period.Last7Days)
-  const retentionOverDays: Array<{
-    firstPeriodKey: string
-    secondPeriodKey: string
-    value: number
-  }> = []
-  for (let i = 0; i < periodKeys.length; i++) {
-    for (let j = 0; j < periodKeys.length - i; j++) {
-      const dailyRetention = await analyticsStore.calculateActivitiesRetention({
-        firstActivity: AnalyticsActivity.Register,
-        firstActivityPeriodKey: periodKeys[i],
-        secondActivity: AnalyticsActivity.GeneralActivity,
-        secondActivityPeriodKey: periodKeys[i + j],
-      })
-
-      retentionOverDays.push({
-        firstPeriodKey: periodKeys[i],
-        secondPeriodKey: periodKeys[i + j],
-        value: dailyRetention,
-      })
-    }
-  }
-
   const monthlyPeriodKeys = periodKeyGenerator.getDiscretePeriodKeys(Period.ThisYear)
   const churnRates: Array<{
     rate: number
@@ -207,16 +176,7 @@ const requestReport = async (
     activityStatistics: yesterdayActivityStatistics,
     activityStatisticsOverTime: analyticsOverTime,
     statisticMeasures,
-    retentionStatistics: [
-      {
-        firstActivity: AnalyticsActivity.Register,
-        secondActivity: AnalyticsActivity.GeneralActivity,
-        retention: {
-          periodKeys,
-          values: retentionOverDays,
-        },
-      },
-    ],
+    retentionStatistics: [],
     churn: {
       periodKeys: monthlyPeriodKeys,
       values: churnRates,

+ 2 - 5
packages/analytics/package.json

@@ -1,17 +1,14 @@
 {
   "name": "@standardnotes/analytics",
-  "version": "1.52.0",
+  "version": "2.0.0",
   "engines": {
     "node": ">=14.0.0 <17.0.0"
   },
+  "private": true,
   "description": "Analytics tools for Standard Notes projects",
   "main": "dist/src/index.js",
   "author": "Standard Notes",
   "types": "dist/src/index.d.ts",
-  "files": [
-    "dist/src/**/*.js",
-    "dist/src/**/*.d.ts"
-  ],
   "publishConfig": {
     "access": "public"
   },

+ 12 - 0
packages/analytics/src/Bootstrap/Container.ts

@@ -43,6 +43,7 @@ import { SubscriptionRefundedEventHandler } from '../Domain/Handler/Subscription
 import { SubscriptionPurchasedEventHandler } from '../Domain/Handler/SubscriptionPurchasedEventHandler'
 import { SubscriptionExpiredEventHandler } from '../Domain/Handler/SubscriptionExpiredEventHandler'
 import { SubscriptionReactivatedEventHandler } from '../Domain/Handler/SubscriptionReactivatedEventHandler'
+import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEventHandler'
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const newrelicFormatter = require('@newrelic/winston-enricher')
@@ -149,6 +150,7 @@ export class ContainerConfigLoader {
     container
       .bind<SubscriptionReactivatedEventHandler>(TYPES.SubscriptionReactivatedEventHandler)
       .to(SubscriptionReactivatedEventHandler)
+    container.bind<RefundProcessedEventHandler>(TYPES.RefundProcessedEventHandler).to(RefundProcessedEventHandler)
 
     // Services
     container.bind<DomainEventFactory>(TYPES.DomainEventFactory).to(DomainEventFactory)
@@ -175,6 +177,16 @@ export class ContainerConfigLoader {
 
     const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
       ['USER_REGISTERED', container.get(TYPES.UserRegisteredEventHandler)],
+      ['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.AccountDeletionRequestedEventHandler)],
+      ['PAYMENT_FAILED', container.get(TYPES.PaymentFailedEventHandler)],
+      ['PAYMENT_SUCCESS', container.get(TYPES.PaymentSuccessEventHandler)],
+      ['SUBSCRIPTION_CANCELLED', container.get(TYPES.SubscriptionCancelledEventHandler)],
+      ['SUBSCRIPTION_RENEWED', container.get(TYPES.SubscriptionRenewedEventHandler)],
+      ['SUBSCRIPTION_REFUNDED', container.get(TYPES.SubscriptionRefundedEventHandler)],
+      ['SUBSCRIPTION_PURCHASED', container.get(TYPES.SubscriptionPurchasedEventHandler)],
+      ['SUBSCRIPTION_EXPIRED', container.get(TYPES.SubscriptionExpiredEventHandler)],
+      ['SUBSCRIPTION_REACTIVATED', container.get(TYPES.SubscriptionReactivatedEventHandler)],
+      ['REFUND_PROCESSED', container.get(TYPES.RefundProcessedEventHandler)],
     ])
 
     if (env.get('SQS_QUEUE_URL', true)) {

+ 1 - 0
packages/analytics/src/Bootstrap/Types.ts

@@ -28,6 +28,7 @@ const TYPES = {
   SubscriptionPurchasedEventHandler: Symbol.for('SubscriptionPurchasedEventHandler'),
   SubscriptionExpiredEventHandler: Symbol.for('SubscriptionExpiredEventHandler'),
   SubscriptionReactivatedEventHandler: Symbol.for('SubscriptionReactivatedEventHandler'),
+  RefundProcessedEventHandler: Symbol.for('RefundProcessedEventHandler'),
   // Services
   DomainEventPublisher: Symbol.for('DomainEventPublisher'),
   DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'),

+ 0 - 8
packages/analytics/src/Domain/Analytics/AnalyticsActivity.ts

@@ -1,10 +1,4 @@
 export enum AnalyticsActivity {
-  GeneralActivity = 'general-activity',
-  GeneralActivityFreeUsers = 'general-activity-free-users',
-  GeneralActivityPaidUsers = 'general-activity-paid-users',
-  EditingItems = 'editing-items',
-  CheckingIntegrity = 'checking-integrity',
-  Login = 'login',
   Register = 'register',
   DeleteAccount = 'DeleteAccount',
   SubscriptionPurchased = 'subscription-purchased',
@@ -13,8 +7,6 @@ export enum AnalyticsActivity {
   SubscriptionCancelled = 'subscription-cancelled',
   SubscriptionExpired = 'subscription-expired',
   SubscriptionReactivated = 'subscription-reactivated',
-  EmailUnbackedUpData = 'email-unbacked-up-data',
-  EmailBackup = 'email-backup',
   LimitedDiscountOfferPurchased = 'limited-discount-offer-purchased',
   PaymentFailed = 'payment-failed',
   PaymentSuccess = 'payment-success',

+ 2 - 32
packages/analytics/src/Domain/Event/DomainEventFactory.spec.ts

@@ -64,22 +64,7 @@ describe('DomainEventFactory', () => {
           },
         ],
         outOfSyncIncidents: 324,
-        retentionStatistics: [
-          {
-            firstActivity: AnalyticsActivity.Register,
-            secondActivity: AnalyticsActivity.Login,
-            retention: {
-              periodKeys: ['2022-10-9'],
-              values: [
-                {
-                  firstPeriodKey: AnalyticsActivity.Register,
-                  secondPeriodKey: AnalyticsActivity.Login,
-                  value: 12,
-                },
-              ],
-            },
-          },
-        ],
+        retentionStatistics: [],
         churn: {
           periodKeys: ['2022-10-9'],
           values: [
@@ -136,22 +121,7 @@ describe('DomainEventFactory', () => {
           ],
         },
         outOfSyncIncidents: 324,
-        retentionStatistics: [
-          {
-            firstActivity: 'register',
-            retention: {
-              periodKeys: ['2022-10-9'],
-              values: [
-                {
-                  firstPeriodKey: 'register',
-                  secondPeriodKey: 'login',
-                  value: 12,
-                },
-              ],
-            },
-            secondActivity: 'login',
-          },
-        ],
+        retentionStatistics: [],
         snjsStatistics: [
           {
             count: 2,

+ 3 - 1
packages/auth/src/Domain/Handler/RefundProcessedEventHandler.spec.ts → packages/analytics/src/Domain/Handler/RefundProcessedEventHandler.spec.ts

@@ -1,9 +1,11 @@
 import 'reflect-metadata'
 
 import { RefundProcessedEvent } from '@standardnotes/domain-events'
-import { Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
 
 import { RefundProcessedEventHandler } from './RefundProcessedEventHandler'
+import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
+import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
+import { Period } from '../Time/Period'
 
 describe('RefundProcessedEventHandler', () => {
   let event: RefundProcessedEvent

+ 3 - 1
packages/auth/src/Domain/Handler/RefundProcessedEventHandler.ts → packages/analytics/src/Domain/Handler/RefundProcessedEventHandler.ts

@@ -1,8 +1,10 @@
-import { Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
 import { DomainEventHandlerInterface, RefundProcessedEvent } from '@standardnotes/domain-events'
 import { inject, injectable } from 'inversify'
 
 import TYPES from '../../Bootstrap/Types'
+import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
+import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
+import { Period } from '../Time/Period'
 
 @injectable()
 export class RefundProcessedEventHandler implements DomainEventHandlerInterface {

+ 0 - 3
packages/analytics/src/Domain/Statistics/StatisticsMeasure.ts

@@ -13,9 +13,6 @@ export enum StatisticsMeasure {
   RegistrationToSubscriptionTime = 'registration-to-subscription-time',
   RemainingSubscriptionTimePercentage = 'remaining-subscription-time-percentage',
   Refunds = 'refunds',
-  NotesCountFreeUsers = 'notes-count-free-users',
-  NotesCountPaidUsers = 'notes-count-paid-users',
-  FilesCount = 'files-count',
   NewCustomers = 'new-customers',
   TotalCustomers = 'total-customers',
 }

+ 0 - 7
packages/analytics/src/Domain/index.ts

@@ -1,7 +0,0 @@
-export * from './Analytics/AnalyticsActivity'
-export * from './Analytics/AnalyticsStoreInterface'
-export * from './Statistics/StatisticsMeasure'
-export * from './Statistics/StatisticsStoreInterface'
-export * from './Time/Period'
-export * from './Time/PeriodKeyGenerator'
-export * from './Time/PeriodKeyGeneratorInterface'

+ 37 - 39
packages/analytics/src/Infra/Redis/RedisAnalyticsStore.spec.ts

@@ -1,6 +1,6 @@
 import * as IORedis from 'ioredis'
-import { Period } from '../../Domain'
 import { AnalyticsActivity } from '../../Domain/Analytics/AnalyticsActivity'
+import { Period } from '../../Domain/Time/Period'
 import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'
 
 import { RedisAnalyticsStore } from './RedisAnalyticsStore'
@@ -35,24 +35,24 @@ describe('RedisAnalyticsStore', () => {
 
     periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
 
-    await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.EditingItems, Period.Last30Days)
+    await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.Register, Period.Last30Days)
 
     expect(redisClient.bitop).toHaveBeenCalledTimes(1)
     expect(redisClient.bitop).toHaveBeenNthCalledWith(
       1,
       'OR',
-      'bitmap:action:editing-items:timespan:2022-4-24-2022-4-26',
-      'bitmap:action:editing-items:timespan:2022-4-24',
-      'bitmap:action:editing-items:timespan:2022-4-25',
-      'bitmap:action:editing-items:timespan:2022-4-26',
+      'bitmap:action:register:timespan:2022-4-24-2022-4-26',
+      'bitmap:action:register:timespan:2022-4-24',
+      'bitmap:action:register:timespan:2022-4-25',
+      'bitmap:action:register:timespan:2022-4-26',
     )
-    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-4-24-2022-4-26')
+    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:register:timespan:2022-4-24-2022-4-26')
   })
 
   it('should not calculate total count over time of activities if period is unsupported', async () => {
     let caughtError = null
     try {
-      await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.EditingItems, Period.LastWeek)
+      await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.Register, Period.LastWeek)
     } catch (error) {
       caughtError = error
     }
@@ -66,7 +66,7 @@ describe('RedisAnalyticsStore', () => {
     redisClient.bitcount = jest.fn().mockReturnValueOnce(70).mockReturnValueOnce(71).mockReturnValueOnce(72)
 
     expect(
-      await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.Last30Days),
+      await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.Register, Period.Last30Days),
     ).toEqual([
       {
         periodKey: '2022-4-24',
@@ -82,9 +82,9 @@ describe('RedisAnalyticsStore', () => {
       },
     ])
 
-    expect(redisClient.bitcount).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-4-24')
-    expect(redisClient.bitcount).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-4-25')
-    expect(redisClient.bitcount).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-4-26')
+    expect(redisClient.bitcount).toHaveBeenNthCalledWith(1, 'bitmap:action:register:timespan:2022-4-24')
+    expect(redisClient.bitcount).toHaveBeenNthCalledWith(2, 'bitmap:action:register:timespan:2022-4-25')
+    expect(redisClient.bitcount).toHaveBeenNthCalledWith(3, 'bitmap:action:register:timespan:2022-4-26')
   })
 
   it('should throw error on calculating total count changes of activities on unsupported period', async () => {
@@ -94,7 +94,7 @@ describe('RedisAnalyticsStore', () => {
 
     let caughtError = null
     try {
-      await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.LastWeek)
+      await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.Register, Period.LastWeek)
     } catch (error) {
       caughtError = error
     }
@@ -105,19 +105,17 @@ describe('RedisAnalyticsStore', () => {
   it('should calculate total count of activities by period', async () => {
     redisClient.bitcount = jest.fn().mockReturnValue(70)
 
-    expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.EditingItems, Period.Yesterday)).toEqual(
-      70,
-    )
+    expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.Register, Period.Yesterday)).toEqual(70)
 
-    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key')
+    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:register:timespan:period-key')
   })
 
   it('should calculate total count of activities by period key', async () => {
     redisClient.bitcount = jest.fn().mockReturnValue(70)
 
-    expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.EditingItems, '2022-10-03')).toEqual(70)
+    expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.Register, '2022-10-03')).toEqual(70)
 
-    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-10-03')
+    expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:register:timespan:2022-10-03')
   })
 
   it('should calculate activity retention', async () => {
@@ -125,7 +123,7 @@ describe('RedisAnalyticsStore', () => {
 
     expect(
       await createStore().calculateActivityRetention(
-        AnalyticsActivity.EditingItems,
+        AnalyticsActivity.Register,
         Period.DayBeforeYesterday,
         Period.Yesterday,
       ),
@@ -133,44 +131,44 @@ describe('RedisAnalyticsStore', () => {
 
     expect(redisClient.bitop).toHaveBeenCalledWith(
       'AND',
-      'bitmap:action:editing-items-editing-items:timespan:period-key',
-      'bitmap:action:editing-items:timespan:period-key',
-      'bitmap:action:editing-items:timespan:period-key',
+      'bitmap:action:register-register:timespan:period-key',
+      'bitmap:action:register:timespan:period-key',
+      'bitmap:action:register:timespan:period-key',
     )
   })
 
   it('shoud tell if activity was done', async () => {
-    await createStore().wasActivityDone(AnalyticsActivity.EditingItems, 123, Period.Yesterday)
+    await createStore().wasActivityDone(AnalyticsActivity.Register, 123, Period.Yesterday)
 
-    expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key', 123)
+    expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:register:timespan:period-key', 123)
   })
 
   it('should mark activity as done', async () => {
-    await createStore().markActivity([AnalyticsActivity.EditingItems], 123, [Period.Today])
+    await createStore().markActivity([AnalyticsActivity.Register], 123, [Period.Today])
 
     expect(pipeline.setbit).toBeCalledTimes(1)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:register:timespan:period-key', 123, 1)
     expect(pipeline.exec).toHaveBeenCalled()
   })
 
   it('should mark activities as done', async () => {
-    await createStore().markActivity([AnalyticsActivity.EditingItems, AnalyticsActivity.EmailUnbackedUpData], 123, [
+    await createStore().markActivity([AnalyticsActivity.Register, AnalyticsActivity.SubscriptionPurchased], 123, [
       Period.Today,
       Period.ThisWeek,
     ])
 
     expect(pipeline.setbit).toBeCalledTimes(4)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:register:timespan:period-key', 123, 1)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:register:timespan:period-key', 123, 1)
     expect(pipeline.setbit).toHaveBeenNthCalledWith(
       3,
-      'bitmap:action:email-unbacked-up-data:timespan:period-key',
+      'bitmap:action:subscription-purchased:timespan:period-key',
       123,
       1,
     )
     expect(pipeline.setbit).toHaveBeenNthCalledWith(
       4,
-      'bitmap:action:email-unbacked-up-data:timespan:period-key',
+      'bitmap:action:subscription-purchased:timespan:period-key',
       123,
       1,
     )
@@ -178,31 +176,31 @@ describe('RedisAnalyticsStore', () => {
   })
 
   it('should unmark activity as done', async () => {
-    await createStore().unmarkActivity([AnalyticsActivity.EditingItems], 123, [Period.Today])
+    await createStore().unmarkActivity([AnalyticsActivity.Register], 123, [Period.Today])
 
     expect(pipeline.setbit).toBeCalledTimes(1)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:register:timespan:period-key', 123, 0)
     expect(pipeline.exec).toHaveBeenCalled()
   })
 
   it('should unmark activities as done', async () => {
-    await createStore().unmarkActivity([AnalyticsActivity.EditingItems, AnalyticsActivity.EmailUnbackedUpData], 123, [
+    await createStore().unmarkActivity([AnalyticsActivity.Register, AnalyticsActivity.SubscriptionPurchased], 123, [
       Period.Today,
       Period.ThisWeek,
     ])
 
     expect(pipeline.setbit).toBeCalledTimes(4)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
-    expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:register:timespan:period-key', 123, 0)
+    expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:register:timespan:period-key', 123, 0)
     expect(pipeline.setbit).toHaveBeenNthCalledWith(
       3,
-      'bitmap:action:email-unbacked-up-data:timespan:period-key',
+      'bitmap:action:subscription-purchased:timespan:period-key',
       123,
       0,
     )
     expect(pipeline.setbit).toHaveBeenNthCalledWith(
       4,
-      'bitmap:action:email-unbacked-up-data:timespan:period-key',
+      'bitmap:action:subscription-purchased:timespan:period-key',
       123,
       0,
     )

+ 2 - 1
packages/analytics/src/Infra/Redis/RedisStatisticsStore.spec.ts

@@ -1,7 +1,8 @@
 import * as IORedis from 'ioredis'
 
-import { Period, PeriodKeyGeneratorInterface } from '../../Domain'
 import { StatisticsMeasure } from '../../Domain/Statistics/StatisticsMeasure'
+import { Period } from '../../Domain/Time/Period'
+import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'
 
 import { RedisStatisticsStore } from './RedisStatisticsStore'
 

+ 2 - 1
packages/analytics/src/Infra/Redis/RedisStatisticsStore.ts

@@ -1,9 +1,10 @@
 import * as IORedis from 'ioredis'
 
-import { Period, PeriodKeyGeneratorInterface } from '../../Domain'
 import { StatisticsMeasure } from '../../Domain/Statistics/StatisticsMeasure'
 
 import { StatisticsStoreInterface } from '../../Domain/Statistics/StatisticsStoreInterface'
+import { Period } from '../../Domain/Time/Period'
+import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'
 
 export class RedisStatisticsStore implements StatisticsStoreInterface {
   constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}

+ 0 - 2
packages/analytics/src/Infra/index.ts

@@ -1,2 +0,0 @@
-export * from './Redis/RedisAnalyticsStore'
-export * from './Redis/RedisStatisticsStore'

+ 0 - 2
packages/analytics/src/index.ts

@@ -1,2 +0,0 @@
-export * from './Domain'
-export * from './Infra'

+ 0 - 1
packages/api-gateway/package.json

@@ -22,7 +22,6 @@
   "dependencies": {
     "@newrelic/winston-enricher": "^4.0.0",
     "@sentry/node": "^7.3.0",
-    "@standardnotes/analytics": "workspace:*",
     "@standardnotes/common": "workspace:^",
     "@standardnotes/domain-events": "workspace:*",
     "@standardnotes/domain-events-infra": "workspace:*",

+ 0 - 17
packages/api-gateway/src/Bootstrap/Container.ts

@@ -2,14 +2,6 @@ import * as winston from 'winston'
 import axios, { AxiosInstance } from 'axios'
 import Redis from 'ioredis'
 import { Container } from 'inversify'
-import {
-  AnalyticsStoreInterface,
-  PeriodKeyGenerator,
-  PeriodKeyGeneratorInterface,
-  RedisAnalyticsStore,
-  RedisStatisticsStore,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
 import { Timer, TimerInterface } from '@standardnotes/time'
 
 import { Env } from './Env'
@@ -18,7 +10,6 @@ import { AuthMiddleware } from '../Controller/AuthMiddleware'
 import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
 import { HttpService } from '../Service/Http/HttpService'
 import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
-import { StatisticsMiddleware } from '../Controller/StatisticsMiddleware'
 import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
 import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
 import { WebSocketAuthMiddleware } from '../Controller/WebSocketAuthMiddleware'
@@ -79,17 +70,9 @@ export class ContainerConfigLoader {
     container
       .bind<SubscriptionTokenAuthMiddleware>(TYPES.SubscriptionTokenAuthMiddleware)
       .to(SubscriptionTokenAuthMiddleware)
-    container.bind<StatisticsMiddleware>(TYPES.StatisticsMiddleware).to(StatisticsMiddleware)
 
     // Services
     container.bind<HttpServiceInterface>(TYPES.HTTPService).to(HttpService)
-    container.bind<PeriodKeyGeneratorInterface>(TYPES.PeriodKeyGenerator).toConstantValue(new PeriodKeyGenerator())
-    container
-      .bind<AnalyticsStoreInterface>(TYPES.AnalyticsStore)
-      .toConstantValue(new RedisAnalyticsStore(container.get(TYPES.PeriodKeyGenerator), container.get(TYPES.Redis)))
-    container
-      .bind<StatisticsStoreInterface>(TYPES.StatisticsStore)
-      .toConstantValue(new RedisStatisticsStore(container.get(TYPES.PeriodKeyGenerator), container.get(TYPES.Redis)))
     container.bind<CrossServiceTokenCacheInterface>(TYPES.CrossServiceTokenCache).to(RedisCrossServiceTokenCache)
     container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
 

+ 0 - 4
packages/api-gateway/src/Bootstrap/Types.ts

@@ -15,17 +15,13 @@ const TYPES = {
   REDIS_EVENTS_CHANNEL: Symbol.for('REDIS_EVENTS_CHANNEL'),
   CROSS_SERVICE_TOKEN_CACHE_TTL: Symbol.for('CROSS_SERVICE_TOKEN_CACHE_TTL'),
   // Middleware
-  StatisticsMiddleware: Symbol.for('StatisticsMiddleware'),
   AuthMiddleware: Symbol.for('AuthMiddleware'),
   WebSocketAuthMiddleware: Symbol.for('WebSocketAuthMiddleware'),
   SubscriptionTokenAuthMiddleware: Symbol.for('SubscriptionTokenAuthMiddleware'),
   // Services
   HTTPService: Symbol.for('HTTPService'),
   CrossServiceTokenCache: Symbol.for('CrossServiceTokenCache'),
-  AnalyticsStore: Symbol.for('AnalyticsStore'),
-  StatisticsStore: Symbol.for('StatisticsStore'),
   Timer: Symbol.for('Timer'),
-  PeriodKeyGenerator: Symbol.for('PeriodKeyGenerator'),
 }
 
 export default TYPES

+ 0 - 13
packages/api-gateway/src/Controller/AuthMiddleware.ts

@@ -1,6 +1,5 @@
 import { CrossServiceTokenData } from '@standardnotes/security'
 import { RoleName } from '@standardnotes/common'
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 import { TimerInterface } from '@standardnotes/time'
 import { NextFunction, Request, Response } from 'express'
 import { inject, injectable } from 'inversify'
@@ -21,7 +20,6 @@ export class AuthMiddleware extends BaseMiddleware {
     @inject(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL) private crossServiceTokenCacheTTL: number,
     @inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
     @inject(TYPES.Timer) private timer: TimerInterface,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {
     super()
@@ -80,17 +78,6 @@ export class AuthMiddleware extends BaseMiddleware {
         decodedToken.roles.length === 1 &&
         decodedToken.roles.find((role) => role.name === RoleName.CoreUser) !== undefined
 
-      await this.analyticsStore.markActivity(
-        [
-          AnalyticsActivity.GeneralActivity,
-          response.locals.freeUser
-            ? AnalyticsActivity.GeneralActivityFreeUsers
-            : AnalyticsActivity.GeneralActivityPaidUsers,
-        ],
-        decodedToken.analyticsId as number,
-        [Period.Today],
-      )
-
       if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
         await this.crossServiceTokenCache.set({
           authorizationHeaderValue: authHeaderValue,

+ 1 - 1
packages/api-gateway/src/Controller/LegacyController.ts

@@ -4,7 +4,7 @@ import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDe
 import TYPES from '../Bootstrap/Types'
 import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
 
-@controller('', TYPES.StatisticsMiddleware)
+@controller('')
 export class LegacyController extends BaseHttpController {
   private AUTH_ROUTES: Map<string, string>
   private PARAMETRIZED_AUTH_ROUTES: Map<string, string>

+ 0 - 31
packages/api-gateway/src/Controller/StatisticsMiddleware.ts

@@ -1,31 +0,0 @@
-import { NextFunction, Request, Response } from 'express'
-import { inject, injectable } from 'inversify'
-import { BaseMiddleware } from 'inversify-express-utils'
-import { Logger } from 'winston'
-import { StatisticsStoreInterface } from '@standardnotes/analytics'
-
-import TYPES from '../Bootstrap/Types'
-
-@injectable()
-export class StatisticsMiddleware extends BaseMiddleware {
-  constructor(
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
-    @inject(TYPES.Logger) private logger: Logger,
-  ) {
-    super()
-  }
-
-  async handler(request: Request, _response: Response, next: NextFunction): Promise<void> {
-    try {
-      const snjsVersion = request.headers['x-snjs-version'] ?? 'unknown'
-      await this.statisticsStore.incrementSNJSVersionUsage(snjsVersion as string)
-
-      const applicationVersion = request.headers['x-application-version'] ?? 'unknown'
-      await this.statisticsStore.incrementApplicationVersionUsage(applicationVersion as string)
-    } catch (error) {
-      this.logger.error(`Could not store analytics data: ${(error as Error).message}`)
-    }
-
-    return next()
-  }
-}

+ 1 - 1
packages/api-gateway/src/Controller/v1/ActionsController.ts

@@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-exp
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1', TYPES.StatisticsMiddleware)
+@controller('/v1')
 export class ActionsController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/FilesController.ts

@@ -5,7 +5,7 @@ import { BaseHttpController, controller, httpPost } from 'inversify-express-util
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/files', TYPES.StatisticsMiddleware)
+@controller('/v1/files')
 export class FilesController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/InvoicesController.ts

@@ -4,7 +4,7 @@ import { inject } from 'inversify'
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1', TYPES.StatisticsMiddleware)
+@controller('/v1')
 export class InvoicesController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/ItemsController.ts

@@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-exp
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/items', TYPES.StatisticsMiddleware, TYPES.AuthMiddleware)
+@controller('/v1/items', TYPES.AuthMiddleware)
 export class ItemsController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/OfflineController.ts

@@ -5,7 +5,7 @@ import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-exp
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/offline', TYPES.StatisticsMiddleware)
+@controller('/v1/offline')
 export class OfflineController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/PaymentsController.ts

@@ -4,7 +4,7 @@ import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } fr
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1', TYPES.StatisticsMiddleware)
+@controller('/v1')
 export class PaymentsController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/RevisionsController.ts

@@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-e
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/items/:item_id/revisions', TYPES.StatisticsMiddleware, TYPES.AuthMiddleware)
+@controller('/v1/items/:item_id/revisions', TYPES.AuthMiddleware)
 export class RevisionsController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/SessionsController.ts

@@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'i
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/sessions', TYPES.StatisticsMiddleware)
+@controller('/v1/sessions')
 export class SessionsController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/SubscriptionInvitesController.ts

@@ -5,7 +5,7 @@ import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'i
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/subscription-invites', TYPES.StatisticsMiddleware)
+@controller('/v1/subscription-invites')
 export class SubscriptionInvitesController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/TokensController.ts

@@ -5,7 +5,7 @@ import { BaseHttpController, controller, httpPost } from 'inversify-express-util
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v1/subscription-tokens', TYPES.StatisticsMiddleware)
+@controller('/v1/subscription-tokens')
 export class TokensController extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v1/UsersController.ts

@@ -16,7 +16,7 @@ import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
 
-@controller('/v1/users', TYPES.StatisticsMiddleware)
+@controller('/v1/users')
 export class UsersController extends BaseHttpController {
   constructor(
     @inject(TYPES.HTTPService) private httpService: HttpServiceInterface,

+ 1 - 1
packages/api-gateway/src/Controller/v2/ActionsControllerV2.ts

@@ -5,7 +5,7 @@ import { BaseHttpController, controller, httpPost } from 'inversify-express-util
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v2', TYPES.StatisticsMiddleware)
+@controller('/v2')
 export class ActionsControllerV2 extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 1 - 1
packages/api-gateway/src/Controller/v2/PaymentsControllerV2.ts

@@ -4,7 +4,7 @@ import { inject } from 'inversify'
 import TYPES from '../../Bootstrap/Types'
 import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
 
-@controller('/v2', TYPES.StatisticsMiddleware)
+@controller('/v2')
 export class PaymentsControllerV2 extends BaseHttpController {
   constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
     super()

+ 0 - 3
packages/auth/.env.sample

@@ -67,6 +67,3 @@ VALET_TOKEN_SECRET=
 VALET_TOKEN_TTL=
 
 WEB_SOCKET_CONNECTION_TOKEN_SECRET=
-
-# (Optional) Analytics
-ANALYTICS_ENABLED=false

+ 1 - 66
packages/auth/bin/backup.ts

@@ -7,7 +7,6 @@ import { Stream } from 'stream'
 import { Logger } from 'winston'
 import * as dayjs from 'dayjs'
 import * as utc from 'dayjs/plugin/utc'
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 
 import { ContainerConfigLoader } from '../src/Bootstrap/Container'
 import TYPES from '../src/Bootstrap/Types'
@@ -19,44 +18,17 @@ import { MuteFailedBackupsEmailsOption, MuteFailedCloudBackupsEmailsOption, Sett
 import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
 import { PermissionName } from '@standardnotes/features'
 import { SettingServiceInterface } from '../src/Domain/Setting/SettingServiceInterface'
-import { AnalyticsEntityRepositoryInterface } from '../src/Domain/Analytics/AnalyticsEntityRepositoryInterface'
 
 const inputArgs = process.argv.slice(2)
 const backupProvider = inputArgs[0]
 const backupFrequency = inputArgs[1]
 
-const shouldEmailBackupBeTriggered = async (
-  analyticsId: number,
-  analyticsStore: AnalyticsStoreInterface,
-): Promise<boolean> => {
-  let periods = [Period.Today, Period.Yesterday]
-  if (backupFrequency === 'weekly') {
-    periods = [Period.ThisWeek, Period.LastWeek]
-  }
-
-  for (const period of periods) {
-    const wasUnBackedUpDataCreatedInPeriod = await analyticsStore.wasActivityDone(
-      AnalyticsActivity.EmailUnbackedUpData,
-      analyticsId,
-      period,
-    )
-    if (wasUnBackedUpDataCreatedInPeriod) {
-      return true
-    }
-  }
-
-  return false
-}
-
 const requestBackups = async (
   settingRepository: SettingRepositoryInterface,
   roleService: RoleServiceInterface,
   settingService: SettingServiceInterface,
   domainEventFactory: DomainEventFactoryInterface,
   domainEventPublisher: DomainEventPublisherInterface,
-  analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
-  analyticsStore: AnalyticsStoreInterface,
-  logger: Logger,
 ): Promise<void> => {
   let settingName: SettingName,
     permissionName: PermissionName,
@@ -123,23 +95,6 @@ const requestBackups = async (
             }
 
             if (backupProvider === 'email') {
-              const analyticsEntity = await analyticsEntityRepository.findOneByUserUuid(setting.setting_user_uuid)
-              if (analyticsEntity === null) {
-                callback()
-
-                return
-              }
-
-              const emailBackupsShouldBeTriggered = await shouldEmailBackupBeTriggered(
-                analyticsEntity.id,
-                analyticsStore,
-              )
-              if (!emailBackupsShouldBeTriggered) {
-                logger.info(
-                  `Email backup for user ${setting.setting_user_uuid} should not be triggered due to inactivity. It will be triggered until further changes.`,
-                )
-              }
-
               await domainEventPublisher.publish(
                 domainEventFactory.createEmailBackupRequestedEvent(
                   setting.setting_user_uuid,
@@ -148,15 +103,6 @@ const requestBackups = async (
                 ),
               )
 
-              await analyticsStore.markActivity([AnalyticsActivity.EmailBackup], analyticsEntity.id, [
-                Period.Today,
-                Period.ThisWeek,
-              ])
-              await analyticsStore.unmarkActivity([AnalyticsActivity.EmailUnbackedUpData], analyticsEntity.id, [
-                Period.Today,
-                Period.ThisWeek,
-              ])
-
               callback()
 
               return
@@ -206,20 +152,9 @@ void container.load().then((container) => {
   const settingService: SettingServiceInterface = container.get(TYPES.SettingService)
   const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
   const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
-  const analyticsEntityRepository: AnalyticsEntityRepositoryInterface = container.get(TYPES.AnalyticsEntityRepository)
-  const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore)
 
   Promise.resolve(
-    requestBackups(
-      settingRepository,
-      roleService,
-      settingService,
-      domainEventFactory,
-      domainEventPublisher,
-      analyticsEntityRepository,
-      analyticsStore,
-      logger,
-    ),
+    requestBackups(settingRepository, roleService, settingService, domainEventFactory, domainEventPublisher),
   )
     .then(() => {
       logger.info(`${backupFrequency} ${backupProvider} backup requesting complete`)

+ 1 - 29
packages/auth/bin/user_email_backup.ts

@@ -5,7 +5,6 @@ import 'newrelic'
 import { Logger } from 'winston'
 import * as dayjs from 'dayjs'
 import * as utc from 'dayjs/plugin/utc'
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 
 import { ContainerConfigLoader } from '../src/Bootstrap/Container'
 import TYPES from '../src/Bootstrap/Types'
@@ -16,7 +15,6 @@ import { SettingRepositoryInterface } from '../src/Domain/Setting/SettingReposit
 import { MuteFailedBackupsEmailsOption, SettingName } from '@standardnotes/settings'
 import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
 import { PermissionName } from '@standardnotes/features'
-import { AnalyticsEntityRepositoryInterface } from '../src/Domain/Analytics/AnalyticsEntityRepositoryInterface'
 import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
 
 const inputArgs = process.argv.slice(2)
@@ -28,8 +26,6 @@ const requestBackups = async (
   roleService: RoleServiceInterface,
   domainEventFactory: DomainEventFactoryInterface,
   domainEventPublisher: DomainEventPublisherInterface,
-  analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
-  analyticsStore: AnalyticsStoreInterface,
 ): Promise<void> => {
   const permissionName = PermissionName.DailyEmailBackup
   const muteEmailsSettingName = SettingName.MuteFailedBackupsEmails
@@ -55,11 +51,6 @@ const requestBackups = async (
     userHasEmailsMuted = emailsMutedSetting.value === muteEmailsSettingValue
   }
 
-  const analyticsEntity = await analyticsEntityRepository.findOneByUserUuid(user.uuid)
-  if (analyticsEntity === null) {
-    return
-  }
-
   await domainEventPublisher.publish(
     domainEventFactory.createEmailBackupRequestedEvent(
       user.uuid,
@@ -68,15 +59,6 @@ const requestBackups = async (
     ),
   )
 
-  await analyticsStore.markActivity([AnalyticsActivity.EmailBackup], analyticsEntity.id, [
-    Period.Today,
-    Period.ThisWeek,
-  ])
-  await analyticsStore.unmarkActivity([AnalyticsActivity.EmailUnbackedUpData], analyticsEntity.id, [
-    Period.Today,
-    Period.ThisWeek,
-  ])
-
   return
 }
 
@@ -96,19 +78,9 @@ void container.load().then((container) => {
   const roleService: RoleServiceInterface = container.get(TYPES.RoleService)
   const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
   const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
-  const analyticsEntityRepository: AnalyticsEntityRepositoryInterface = container.get(TYPES.AnalyticsEntityRepository)
-  const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore)
 
   Promise.resolve(
-    requestBackups(
-      userRepository,
-      settingRepository,
-      roleService,
-      domainEventFactory,
-      domainEventPublisher,
-      analyticsEntityRepository,
-      analyticsStore,
-    ),
+    requestBackups(userRepository, settingRepository, roleService, domainEventFactory, domainEventPublisher),
   )
     .then(() => {
       logger.info(`Email backup requesting complete for ${backupEmail}`)

+ 0 - 1
packages/auth/package.json

@@ -32,7 +32,6 @@
   "dependencies": {
     "@newrelic/winston-enricher": "^4.0.0",
     "@sentry/node": "^7.3.0",
-    "@standardnotes/analytics": "workspace:*",
     "@standardnotes/api": "^1.19.0",
     "@standardnotes/common": "workspace:*",
     "@standardnotes/domain-events": "workspace:*",

+ 0 - 40
packages/auth/src/Bootstrap/Container.ts

@@ -9,13 +9,6 @@ import {
 } from '@standardnotes/domain-events'
 import { TimerInterface, Timer } from '@standardnotes/time'
 import { UAParser } from 'ua-parser-js'
-import {
-  AnalyticsStoreInterface,
-  PeriodKeyGenerator,
-  RedisAnalyticsStore,
-  RedisStatisticsStore,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
 
 import { Env } from './Env'
 import TYPES from './Types'
@@ -191,21 +184,13 @@ import { RoleRepositoryInterface } from '../Domain/Role/RoleRepositoryInterface'
 import { RevokedSessionRepositoryInterface } from '../Domain/Session/RevokedSessionRepositoryInterface'
 import { SessionRepositoryInterface } from '../Domain/Session/SessionRepositoryInterface'
 import { UserRepositoryInterface } from '../Domain/User/UserRepositoryInterface'
-import { AnalyticsEntity } from '../Domain/Analytics/AnalyticsEntity'
-import { AnalyticsEntityRepositoryInterface } from '../Domain/Analytics/AnalyticsEntityRepositoryInterface'
-import { MySQLAnalyticsEntityRepository } from '../Infra/MySQL/MySQLAnalyticsEntityRepository'
-import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 import { AuthController } from '../Controller/AuthController'
 import { VerifyPredicate } from '../Domain/UseCase/VerifyPredicate/VerifyPredicate'
 import { PredicateVerificationRequestedEventHandler } from '../Domain/Handler/PredicateVerificationRequestedEventHandler'
-import { PaymentFailedEventHandler } from '../Domain/Handler/PaymentFailedEventHandler'
-import { PaymentSuccessEventHandler } from '../Domain/Handler/PaymentSuccessEventHandler'
-import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEventHandler'
 import { SubscriptionInvitesController } from '../Controller/SubscriptionInvitesController'
 import { CreateCrossServiceToken } from '../Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
 import { ProcessUserRequest } from '../Domain/UseCase/ProcessUserRequest/ProcessUserRequest'
 import { UserRequestsController } from '../Controller/UserRequestsController'
-import { SubscriptionReactivatedEventHandler } from '../Domain/Handler/SubscriptionReactivatedEventHandler'
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const newrelicFormatter = require('@newrelic/winston-enricher')
@@ -301,9 +286,6 @@ export class ContainerConfigLoader {
       .bind<SharedSubscriptionInvitationRepositoryInterface>(TYPES.SharedSubscriptionInvitationRepository)
       .to(MySQLSharedSubscriptionInvitationRepository)
     container.bind<PKCERepositoryInterface>(TYPES.PKCERepository).to(RedisPKCERepository)
-    container
-      .bind<AnalyticsEntityRepositoryInterface>(TYPES.AnalyticsEntityRepository)
-      .to(MySQLAnalyticsEntityRepository)
 
     // ORM
     container
@@ -332,9 +314,6 @@ export class ContainerConfigLoader {
     container
       .bind<Repository<UserSubscription>>(TYPES.ORMUserSubscriptionRepository)
       .toConstantValue(AppDataSource.getRepository(UserSubscription))
-    container
-      .bind<Repository<AnalyticsEntity>>(TYPES.ORMAnalyticsEntityRepository)
-      .toConstantValue(AppDataSource.getRepository(AnalyticsEntity))
 
     // Middleware
     container.bind<AuthMiddleware>(TYPES.AuthMiddleware).to(AuthMiddleware)
@@ -379,7 +358,6 @@ export class ContainerConfigLoader {
     container
       .bind(TYPES.DISABLE_USER_REGISTRATION)
       .toConstantValue(env.get('DISABLE_USER_REGISTRATION', true) === 'true')
-    container.bind(TYPES.ANALYTICS_ENABLED).toConstantValue(env.get('ANALYTICS_ENABLED', true) === 'true')
     container.bind(TYPES.SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
     container.bind(TYPES.SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
     container.bind(TYPES.SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL', true))
@@ -439,7 +417,6 @@ export class ContainerConfigLoader {
       .bind<ListSharedSubscriptionInvitations>(TYPES.ListSharedSubscriptionInvitations)
       .to(ListSharedSubscriptionInvitations)
     container.bind<GetSubscriptionSetting>(TYPES.GetSubscriptionSetting).to(GetSubscriptionSetting)
-    container.bind<GetUserAnalyticsId>(TYPES.GetUserAnalyticsId).to(GetUserAnalyticsId)
     container.bind<VerifyPredicate>(TYPES.VerifyPredicate).to(VerifyPredicate)
     container.bind<CreateCrossServiceToken>(TYPES.CreateCrossServiceToken).to(CreateCrossServiceToken)
     container.bind<ProcessUserRequest>(TYPES.ProcessUserRequest).to(ProcessUserRequest)
@@ -491,12 +468,6 @@ export class ContainerConfigLoader {
     container
       .bind<PredicateVerificationRequestedEventHandler>(TYPES.PredicateVerificationRequestedEventHandler)
       .to(PredicateVerificationRequestedEventHandler)
-    container.bind<PaymentFailedEventHandler>(TYPES.PaymentFailedEventHandler).to(PaymentFailedEventHandler)
-    container.bind<PaymentSuccessEventHandler>(TYPES.PaymentSuccessEventHandler).to(PaymentSuccessEventHandler)
-    container.bind<RefundProcessedEventHandler>(TYPES.RefundProcessedEventHandler).to(RefundProcessedEventHandler)
-    container
-      .bind<SubscriptionReactivatedEventHandler>(TYPES.SubscriptionReactivatedEventHandler)
-      .to(SubscriptionReactivatedEventHandler)
 
     // Services
     container.bind<UAParser>(TYPES.DeviceDetector).toConstantValue(new UAParser())
@@ -562,13 +533,6 @@ export class ContainerConfigLoader {
       .bind<SelectorInterface<boolean>>(TYPES.BooleanSelector)
       .toConstantValue(new DeterministicSelector<boolean>())
     container.bind<UserSubscriptionServiceInterface>(TYPES.UserSubscriptionService).to(UserSubscriptionService)
-    const periodKeyGenerator = new PeriodKeyGenerator()
-    container
-      .bind<AnalyticsStoreInterface>(TYPES.AnalyticsStore)
-      .toConstantValue(new RedisAnalyticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
-    container
-      .bind<StatisticsStoreInterface>(TYPES.StatisticsStore)
-      .toConstantValue(new RedisStatisticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
     container.bind<ValidatorInterface<Uuid>>(TYPES.UuidValidator).toConstantValue(new UuidValidator())
 
     if (env.get('SNS_TOPIC_ARN', true)) {
@@ -605,10 +569,6 @@ export class ContainerConfigLoader {
       ],
       ['SHARED_SUBSCRIPTION_INVITATION_CREATED', container.get(TYPES.SharedSubscriptionInvitationCreatedEventHandler)],
       ['PREDICATE_VERIFICATION_REQUESTED', container.get(TYPES.PredicateVerificationRequestedEventHandler)],
-      ['PAYMENT_FAILED', container.get(TYPES.PaymentFailedEventHandler)],
-      ['PAYMENT_SUCCESS', container.get(TYPES.PaymentSuccessEventHandler)],
-      ['REFUND_PROCESSED', container.get(TYPES.RefundProcessedEventHandler)],
-      ['SUBSCRIPTION_REACTIVATED', container.get(TYPES.SubscriptionReactivatedEventHandler)],
     ])
 
     if (env.get('SQS_QUEUE_URL', true)) {

+ 0 - 2
packages/auth/src/Bootstrap/DataSource.ts

@@ -1,5 +1,4 @@
 import { DataSource, LoggerOptions } from 'typeorm'
-import { AnalyticsEntity } from '../Domain/Analytics/AnalyticsEntity'
 import { Permission } from '../Domain/Permission/Permission'
 import { Role } from '../Domain/Role/Role'
 import { RevokedSession } from '../Domain/Session/RevokedSession'
@@ -57,7 +56,6 @@ export const AppDataSource = new DataSource({
     OfflineSetting,
     SharedSubscriptionInvitation,
     SubscriptionSetting,
-    AnalyticsEntity,
   ],
   migrations: [env.get('DB_MIGRATIONS_PATH', true) ?? 'dist/migrations/*.js'],
   migrationsRun: true,

+ 0 - 10
packages/auth/src/Bootstrap/Types.ts

@@ -23,7 +23,6 @@ const TYPES = {
   OfflineSubscriptionTokenRepository: Symbol.for('OfflineSubscriptionTokenRepository'),
   SharedSubscriptionInvitationRepository: Symbol.for('SharedSubscriptionInvitationRepository'),
   PKCERepository: Symbol.for('PKCERepository'),
-  AnalyticsEntityRepository: Symbol.for('AnalyticsEntityRepository'),
   // ORM
   ORMOfflineSettingRepository: Symbol.for('ORMOfflineSettingRepository'),
   ORMOfflineUserSubscriptionRepository: Symbol.for('ORMOfflineUserSubscriptionRepository'),
@@ -35,7 +34,6 @@ const TYPES = {
   ORMSubscriptionSettingRepository: Symbol.for('ORMSubscriptionSettingRepository'),
   ORMUserRepository: Symbol.for('ORMUserRepository'),
   ORMUserSubscriptionRepository: Symbol.for('ORMUserSubscriptionRepository'),
-  ORMAnalyticsEntityRepository: Symbol.for('ORMAnalyticsEntityRepository'),
   // Middleware
   AuthMiddleware: Symbol.for('AuthMiddleware'),
   ApiGatewayAuthMiddleware: Symbol.for('ApiGatewayAuthMiddleware'),
@@ -71,7 +69,6 @@ const TYPES = {
   PSEUDO_KEY_PARAMS_KEY: Symbol.for('PSEUDO_KEY_PARAMS_KEY'),
   REDIS_URL: Symbol.for('REDIS_URL'),
   DISABLE_USER_REGISTRATION: Symbol.for('DISABLE_USER_REGISTRATION'),
-  ANALYTICS_ENABLED: Symbol.for('ANALYTICS_ENABLED'),
   SNS_TOPIC_ARN: Symbol.for('SNS_TOPIC_ARN'),
   SNS_AWS_REGION: Symbol.for('SNS_AWS_REGION'),
   SQS_QUEUE_URL: Symbol.for('SQS_QUEUE_URL'),
@@ -119,7 +116,6 @@ const TYPES = {
   CancelSharedSubscriptionInvitation: Symbol.for('CancelSharedSubscriptionInvitation'),
   ListSharedSubscriptionInvitations: Symbol.for('ListSharedSubscriptionInvitations'),
   GetSubscriptionSetting: Symbol.for('GetSubscriptionSetting'),
-  GetUserAnalyticsId: Symbol.for('GetUserAnalyticsId'),
   VerifyPredicate: Symbol.for('VerifyPredicate'),
   CreateCrossServiceToken: Symbol.for('CreateCrossServiceToken'),
   ProcessUserRequest: Symbol.for('ProcessUserRequest'),
@@ -142,10 +138,6 @@ const TYPES = {
   UserDisabledSessionUserAgentLoggingEventHandler: Symbol.for('UserDisabledSessionUserAgentLoggingEventHandler'),
   SharedSubscriptionInvitationCreatedEventHandler: Symbol.for('SharedSubscriptionInvitationCreatedEventHandler'),
   PredicateVerificationRequestedEventHandler: Symbol.for('PredicateVerificationRequestedEventHandler'),
-  PaymentFailedEventHandler: Symbol.for('PaymentFailedEventHandler'),
-  PaymentSuccessEventHandler: Symbol.for('PaymentSuccessEventHandler'),
-  RefundProcessedEventHandler: Symbol.for('RefundProcessedEventHandler'),
-  SubscriptionReactivatedEventHandler: Symbol.for('SubscriptionReactivatedEventHandler'),
   // Services
   DeviceDetector: Symbol.for('DeviceDetector'),
   SessionService: Symbol.for('SessionService'),
@@ -187,8 +179,6 @@ const TYPES = {
   ProtocolVersionSelector: Symbol.for('ProtocolVersionSelector'),
   BooleanSelector: Symbol.for('BooleanSelector'),
   UserSubscriptionService: Symbol.for('UserSubscriptionService'),
-  AnalyticsStore: Symbol.for('AnalyticsStore'),
-  StatisticsStore: Symbol.for('StatisticsStore'),
   UuidValidator: Symbol.for('UuidValidator'),
 }
 

+ 0 - 7
packages/auth/src/Controller/SubscriptionTokensController.spec.ts

@@ -13,7 +13,6 @@ import { Role } from '../Domain/Role/Role'
 import { SettingServiceInterface } from '../Domain/Setting/SettingServiceInterface'
 import { Setting } from '../Domain/Setting/Setting'
 import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
-import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 describe('SubscriptionTokensController', () => {
   let createSubscriptionToken: CreateSubscriptionToken
@@ -24,7 +23,6 @@ describe('SubscriptionTokensController', () => {
   let settingService: SettingServiceInterface
   let extensionKeySetting: Setting
   let tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>
-  let getUserAnalyticsId: GetUserAnalyticsId
 
   let request: express.Request
   let response: express.Response
@@ -39,7 +37,6 @@ describe('SubscriptionTokensController', () => {
       userProjector,
       roleProjector,
       tokenEncoder,
-      getUserAnalyticsId,
       jwtTTL,
     )
 
@@ -78,9 +75,6 @@ describe('SubscriptionTokensController', () => {
     tokenEncoder = {} as jest.Mocked<TokenEncoderInterface<CrossServiceTokenData>>
     tokenEncoder.encodeExpirableToken = jest.fn().mockReturnValue('foobar')
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 123 })
-
     request = {
       headers: {},
       body: {},
@@ -137,7 +131,6 @@ describe('SubscriptionTokensController', () => {
 
     expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
       {
-        analyticsId: 123,
         extensionKey: 'abc123',
         roles: [
           {

+ 0 - 5
packages/auth/src/Controller/SubscriptionTokensController.ts

@@ -16,7 +16,6 @@ import { Role } from '../Domain/Role/Role'
 import { SettingServiceInterface } from '../Domain/Setting/SettingServiceInterface'
 import { AuthenticateSubscriptionToken } from '../Domain/UseCase/AuthenticateSubscriptionToken/AuthenticateSubscriptionToken'
 import { CreateSubscriptionToken } from '../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
-import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 import { User } from '../Domain/User/User'
 import { ProjectorInterface } from '../Projection/ProjectorInterface'
 
@@ -29,7 +28,6 @@ export class SubscriptionTokensController extends BaseHttpController {
     @inject(TYPES.UserProjector) private userProjector: ProjectorInterface<User>,
     @inject(TYPES.RoleProjector) private roleProjector: ProjectorInterface<Role>,
     @inject(TYPES.CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
     @inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number,
   ) {
     super()
@@ -88,13 +86,10 @@ export class SubscriptionTokensController extends BaseHttpController {
 
     const roles = await user.roles
 
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-
     const authTokenData: CrossServiceTokenData = {
       user: await this.projectUser(user),
       roles: await this.projectRoles(roles),
       extensionKey,
-      analyticsId,
     }
 
     const authToken = this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL)

+ 0 - 19
packages/auth/src/Domain/Analytics/AnalyticsEntity.ts

@@ -1,19 +0,0 @@
-import { Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm'
-import { User } from '../User/User'
-
-@Entity({ name: 'analytics_entities' })
-export class AnalyticsEntity {
-  @PrimaryGeneratedColumn()
-  declare id: number
-
-  @OneToOne(
-    /* istanbul ignore next */
-    () => User,
-    /* istanbul ignore next */
-    (user) => user.analyticsEntity,
-    /* istanbul ignore next */
-    { onDelete: 'CASCADE', nullable: false, lazy: true, eager: false },
-  )
-  @JoinColumn({ name: 'user_uuid', referencedColumnName: 'uuid' })
-  declare user: Promise<User>
-}

+ 0 - 7
packages/auth/src/Domain/Analytics/AnalyticsEntityRepositoryInterface.ts

@@ -1,7 +0,0 @@
-import { Uuid } from '@standardnotes/common'
-import { AnalyticsEntity } from './AnalyticsEntity'
-
-export interface AnalyticsEntityRepositoryInterface {
-  save(analyticsEntity: AnalyticsEntity): Promise<AnalyticsEntity>
-  findOneByUserUuid(userUuid: Uuid): Promise<AnalyticsEntity | null>
-}

+ 0 - 24
packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.spec.ts

@@ -11,9 +11,6 @@ import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterfac
 import { User } from '../User/User'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { AccountDeletionRequestedEventHandler } from './AccountDeletionRequestedEventHandler'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { AnalyticsStoreInterface, StatisticsStoreInterface } from '@standardnotes/analytics'
-import { TimerInterface } from '@standardnotes/time'
 
 describe('AccountDeletionRequestedEventHandler', () => {
   let userRepository: UserRepositoryInterface
@@ -26,10 +23,6 @@ describe('AccountDeletionRequestedEventHandler', () => {
   let revokedSession: RevokedSession
   let user: User
   let event: AccountDeletionRequestedEvent
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-  let statisticsStore: StatisticsStoreInterface
-  let timer: TimerInterface
 
   const createHandler = () =>
     new AccountDeletionRequestedEventHandler(
@@ -37,10 +30,6 @@ describe('AccountDeletionRequestedEventHandler', () => {
       sessionRepository,
       ephemeralSessionRepository,
       revokedSessionRepository,
-      getUserAnalyticsId,
-      analyticsStore,
-      statisticsStore,
-      timer,
       logger,
     )
 
@@ -84,22 +73,9 @@ describe('AccountDeletionRequestedEventHandler', () => {
       regularSubscriptionUuid: '2-3-4',
     }
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.info = jest.fn()
     logger.warn = jest.fn()
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.incrementMeasure = jest.fn()
-
-    timer = {} as jest.Mocked<TimerInterface>
-    timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123)
-    timer.convertDateToMicroseconds = jest.fn().mockReturnValue(100)
   })
 
   it('should remove a user', async () => {

+ 0 - 28
packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.ts

@@ -1,19 +1,10 @@
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
 import { AccountDeletionRequestedEvent, DomainEventHandlerInterface } from '@standardnotes/domain-events'
-import { TimerInterface } from '@standardnotes/time'
 import { inject, injectable } from 'inversify'
 import { Logger } from 'winston'
 import TYPES from '../../Bootstrap/Types'
 import { EphemeralSessionRepositoryInterface } from '../Session/EphemeralSessionRepositoryInterface'
 import { RevokedSessionRepositoryInterface } from '../Session/RevokedSessionRepositoryInterface'
 import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterface'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 
 @injectable()
@@ -23,10 +14,6 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
     @inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface,
     @inject(TYPES.EphemeralSessionRepository) private ephemeralSessionRepository: EphemeralSessionRepositoryInterface,
     @inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
-    @inject(TYPES.Timer) private timer: TimerInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -41,21 +28,6 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
 
     await this.removeSessions(event.payload.userUuid)
 
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.DeleteAccount], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-
-    const registrationLength =
-      this.timer.getTimestampInMicroseconds() - this.timer.convertDateToMicroseconds(user.createdAt)
-    await this.statisticsStore.incrementMeasure(StatisticsMeasure.RegistrationLength, registrationLength, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-
     await this.userRepository.remove(user)
 
     this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)

+ 0 - 51
packages/auth/src/Domain/Handler/PaymentFailedEventHandler.spec.ts

@@ -1,51 +0,0 @@
-import 'reflect-metadata'
-
-import { PaymentFailedEvent } from '@standardnotes/domain-events'
-import { AnalyticsStoreInterface } from '@standardnotes/analytics'
-
-import { PaymentFailedEventHandler } from './PaymentFailedEventHandler'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-import { User } from '../User/User'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-
-describe('PaymentFailedEventHandler', () => {
-  let userRepository: UserRepositoryInterface
-  let event: PaymentFailedEvent
-  let user: User
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-
-  const createHandler = () => new PaymentFailedEventHandler(userRepository, getUserAnalyticsId, analyticsStore)
-
-  beforeEach(() => {
-    user = {} as jest.Mocked<User>
-
-    userRepository = {} as jest.Mocked<UserRepositoryInterface>
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
-
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
-    event = {} as jest.Mocked<PaymentFailedEvent>
-    event.payload = {
-      userEmail: 'test@test.com',
-    }
-  })
-
-  it('should mark payment failed for analytics', async () => {
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalled()
-  })
-
-  it('should not mark payment failed for analytics if user is not found', async () => {
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
-  })
-})

+ 0 - 30
packages/auth/src/Domain/Handler/PaymentFailedEventHandler.ts

@@ -1,30 +0,0 @@
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
-import { DomainEventHandlerInterface, PaymentFailedEvent } from '@standardnotes/domain-events'
-import { inject, injectable } from 'inversify'
-
-import TYPES from '../../Bootstrap/Types'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-
-@injectable()
-export class PaymentFailedEventHandler implements DomainEventHandlerInterface {
-  constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-  ) {}
-
-  async handle(event: PaymentFailedEvent): Promise<void> {
-    const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
-    if (user === null) {
-      return
-    }
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.PaymentFailed], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-  }
-}

+ 0 - 90
packages/auth/src/Domain/Handler/PaymentSuccessEventHandler.spec.ts

@@ -1,90 +0,0 @@
-import 'reflect-metadata'
-
-import { PaymentSuccessEvent } from '@standardnotes/domain-events'
-import { AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
-
-import { PaymentSuccessEventHandler } from './PaymentSuccessEventHandler'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-import { User } from '../User/User'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { Logger } from 'winston'
-
-describe('PaymentSuccessEventHandler', () => {
-  let userRepository: UserRepositoryInterface
-  let event: PaymentSuccessEvent
-  let user: User
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-  let statisticsStore: StatisticsStoreInterface
-  let logger: Logger
-
-  const createHandler = () =>
-    new PaymentSuccessEventHandler(userRepository, getUserAnalyticsId, analyticsStore, statisticsStore, logger)
-
-  beforeEach(() => {
-    user = {} as jest.Mocked<User>
-
-    userRepository = {} as jest.Mocked<UserRepositoryInterface>
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
-
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.incrementMeasure = jest.fn()
-
-    event = {} as jest.Mocked<PaymentSuccessEvent>
-    event.payload = {
-      userEmail: 'test@test.com',
-      amount: 12.45,
-      billingFrequency: 12,
-      paymentType: 'initial',
-      subscriptionName: 'PRO_PLAN',
-    }
-
-    logger = {} as jest.Mocked<Logger>
-    logger.warn = jest.fn()
-  })
-
-  it('should mark payment success for analytics', async () => {
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalled()
-    expect(statisticsStore.incrementMeasure).toHaveBeenNthCalledWith(
-      2,
-      'pro-subscription-initial-annual-payments-income',
-      12.45,
-      [Period.Today, Period.ThisWeek, Period.ThisMonth],
-    )
-  })
-
-  it('should mark non-detailed payment success statistics for analytics', async () => {
-    event.payload = {
-      userEmail: 'test@test.com',
-      amount: 12.45,
-      billingFrequency: 13,
-      paymentType: 'initial',
-      subscriptionName: 'PRO_PLAN',
-    }
-
-    await createHandler().handle(event)
-
-    expect(statisticsStore.incrementMeasure).toBeCalledTimes(1)
-    expect(statisticsStore.incrementMeasure).toHaveBeenNthCalledWith(1, 'income', 12.45, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-  })
-
-  it('should not mark payment failed for analytics if user is not found', async () => {
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
-  })
-})

+ 0 - 102
packages/auth/src/Domain/Handler/PaymentSuccessEventHandler.ts

@@ -1,102 +0,0 @@
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
-import { PaymentType, SubscriptionBillingFrequency, SubscriptionName } from '@standardnotes/common'
-import { DomainEventHandlerInterface, PaymentSuccessEvent } from '@standardnotes/domain-events'
-import { inject, injectable } from 'inversify'
-import { Logger } from 'winston'
-
-import TYPES from '../../Bootstrap/Types'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-
-@injectable()
-export class PaymentSuccessEventHandler implements DomainEventHandlerInterface {
-  private readonly DETAILED_MEASURES = new Map([
-    [
-      SubscriptionName.PlusPlan,
-      new Map([
-        [
-          PaymentType.Initial,
-          new Map([
-            [SubscriptionBillingFrequency.Monthly, StatisticsMeasure.PlusSubscriptionInitialMonthlyPaymentsIncome],
-            [SubscriptionBillingFrequency.Annual, StatisticsMeasure.PlusSubscriptionInitialAnnualPaymentsIncome],
-          ]),
-        ],
-        [
-          PaymentType.Renewal,
-          new Map([
-            [SubscriptionBillingFrequency.Monthly, StatisticsMeasure.PlusSubscriptionRenewingMonthlyPaymentsIncome],
-            [SubscriptionBillingFrequency.Annual, StatisticsMeasure.PlusSubscriptionRenewingAnnualPaymentsIncome],
-          ]),
-        ],
-      ]),
-    ],
-    [
-      SubscriptionName.ProPlan,
-      new Map([
-        [
-          PaymentType.Initial,
-          new Map([
-            [SubscriptionBillingFrequency.Monthly, StatisticsMeasure.ProSubscriptionInitialMonthlyPaymentsIncome],
-            [SubscriptionBillingFrequency.Annual, StatisticsMeasure.ProSubscriptionInitialAnnualPaymentsIncome],
-          ]),
-        ],
-        [
-          PaymentType.Renewal,
-          new Map([
-            [SubscriptionBillingFrequency.Monthly, StatisticsMeasure.ProSubscriptionRenewingMonthlyPaymentsIncome],
-            [SubscriptionBillingFrequency.Annual, StatisticsMeasure.ProSubscriptionRenewingAnnualPaymentsIncome],
-          ]),
-        ],
-      ]),
-    ],
-  ])
-
-  constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
-    @inject(TYPES.Logger) private logger: Logger,
-  ) {}
-
-  async handle(event: PaymentSuccessEvent): Promise<void> {
-    const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
-    if (user === null) {
-      return
-    }
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.PaymentSuccess], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-
-    const statisticMeasures = [StatisticsMeasure.Income]
-
-    const detailedMeasure = this.DETAILED_MEASURES.get(event.payload.subscriptionName as SubscriptionName)
-      ?.get(event.payload.paymentType as PaymentType)
-      ?.get(event.payload.billingFrequency as SubscriptionBillingFrequency)
-    if (detailedMeasure !== undefined) {
-      statisticMeasures.push(detailedMeasure)
-    } else {
-      this.logger.warn(
-        `Could not find detailed measure for: subscription - ${event.payload.subscriptionName}, payment type - ${event.payload.paymentType}, billing frequency - ${event.payload.billingFrequency}`,
-      )
-    }
-
-    for (const measure of statisticMeasures) {
-      await this.statisticsStore.incrementMeasure(measure, event.payload.amount, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-      ])
-    }
-  }
-}

+ 1 - 65
packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.spec.ts

@@ -8,54 +8,19 @@ import * as dayjs from 'dayjs'
 import { SubscriptionCancelledEventHandler } from './SubscriptionCancelledEventHandler'
 import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
-import { AnalyticsStoreInterface, Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-import { User } from '../User/User'
-import { UserSubscription } from '../Subscription/UserSubscription'
 
 describe('SubscriptionCancelledEventHandler', () => {
   let userSubscriptionRepository: UserSubscriptionRepositoryInterface
   let offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface
   let event: SubscriptionCancelledEvent
-  let userRepository: UserRepositoryInterface
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-  let statisticsStore: StatisticsStoreInterface
   let timestamp: number
 
   const createHandler = () =>
-    new SubscriptionCancelledEventHandler(
-      userSubscriptionRepository,
-      offlineUserSubscriptionRepository,
-      userRepository,
-      getUserAnalyticsId,
-      analyticsStore,
-      statisticsStore,
-    )
+    new SubscriptionCancelledEventHandler(userSubscriptionRepository, offlineUserSubscriptionRepository)
 
   beforeEach(() => {
-    const user = { uuid: '1-2-3' } as jest.Mocked<User>
-
-    userRepository = {} as jest.Mocked<UserRepositoryInterface>
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
-
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.incrementMeasure = jest.fn()
-
-    const userSubscription = {
-      createdAt: 1642395451515000,
-    } as jest.Mocked<UserSubscription>
-
     userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
     userSubscriptionRepository.updateCancelled = jest.fn()
-    userSubscriptionRepository.findBySubscriptionId = jest.fn().mockReturnValue([userSubscription])
 
     offlineUserSubscriptionRepository = {} as jest.Mocked<OfflineUserSubscriptionRepositoryInterface>
     offlineUserSubscriptionRepository.updateCancelled = jest.fn()
@@ -83,35 +48,6 @@ describe('SubscriptionCancelledEventHandler', () => {
     await createHandler().handle(event)
 
     expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, 1642395451516000)
-    expect(analyticsStore.markActivity).toHaveBeenCalled()
-    expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith(StatisticsMeasure.SubscriptionLength, 1000, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-  })
-
-  it('should not track statistics for subscriptions that are in a legacy 5 year plan', async () => {
-    event.payload.timestamp = 1642395451516000
-
-    const userSubscription = {
-      createdAt: 1642395451515000,
-      endsAt: 1642395451515000 + 126_230_400_000_001,
-    } as jest.Mocked<UserSubscription>
-    userSubscriptionRepository.findBySubscriptionId = jest.fn().mockReturnValue([userSubscription])
-
-    await createHandler().handle(event)
-
-    expect(statisticsStore.incrementMeasure).not.toHaveBeenCalled()
-  })
-
-  it('should update subscription cancelled - user not found', async () => {
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
-
-    await createHandler().handle(event)
-
-    expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, timestamp)
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
   })
 
   it('should update offline subscription cancelled', async () => {

+ 1 - 61
packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.ts

@@ -1,19 +1,9 @@
 import { DomainEventHandlerInterface, SubscriptionCancelledEvent } from '@standardnotes/domain-events'
 import { inject, injectable } from 'inversify'
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
 
 import TYPES from '../../Bootstrap/Types'
 import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { UserSubscription } from '../Subscription/UserSubscription'
 
 @injectable()
 export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
@@ -21,24 +11,9 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
     @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
     @inject(TYPES.OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
   ) {}
-  async handle(event: SubscriptionCancelledEvent): Promise<void> {
-    const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
-    if (user !== null) {
-      const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-      await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionCancelled], analyticsId, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-      ])
-    }
-
-    await this.trackSubscriptionStatistics(event)
 
+  async handle(event: SubscriptionCancelledEvent): Promise<void> {
     if (event.payload.offline) {
       await this.updateOfflineSubscriptionCancelled(event.payload.subscriptionId, event.payload.timestamp)
 
@@ -55,39 +30,4 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
   private async updateOfflineSubscriptionCancelled(subscriptionId: number, timestamp: number): Promise<void> {
     await this.offlineUserSubscriptionRepository.updateCancelled(subscriptionId, true, timestamp)
   }
-
-  private async trackSubscriptionStatistics(event: SubscriptionCancelledEvent) {
-    const subscriptions = await this.userSubscriptionRepository.findBySubscriptionId(event.payload.subscriptionId)
-    if (subscriptions.length !== 0) {
-      const lastSubscription = subscriptions.shift() as UserSubscription
-      if (this.isLegacy5yearSubscriptionPlan(lastSubscription)) {
-        return
-      }
-
-      const subscriptionLength = event.payload.timestamp - lastSubscription.createdAt
-      await this.statisticsStore.incrementMeasure(StatisticsMeasure.SubscriptionLength, subscriptionLength, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-      ])
-
-      const lastPurchaseTime = lastSubscription.renewedAt ?? lastSubscription.updatedAt
-      const remainingSubscriptionTime = lastSubscription.endsAt - event.payload.timestamp
-      const totalSubscriptionTime = lastSubscription.endsAt - lastPurchaseTime
-
-      const remainingSubscriptionPercentage = Math.floor((remainingSubscriptionTime / totalSubscriptionTime) * 100)
-
-      await this.statisticsStore.incrementMeasure(
-        StatisticsMeasure.RemainingSubscriptionTimePercentage,
-        remainingSubscriptionPercentage,
-        [Period.Today, Period.ThisWeek, Period.ThisMonth],
-      )
-    }
-  }
-
-  private isLegacy5yearSubscriptionPlan(subscription: UserSubscription) {
-    const fourYearsInMicroseconds = 126_230_400_000_000
-
-    return subscription.endsAt - subscription.createdAt > fourYearsInMicroseconds
-  }
 }

+ 0 - 17
packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.spec.ts

@@ -13,8 +13,6 @@ import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscri
 import { RoleServiceInterface } from '../Role/RoleServiceInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
 import { UserSubscription } from '../Subscription/UserSubscription'
-import { AnalyticsStoreInterface, StatisticsStoreInterface } from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 describe('SubscriptionExpiredEventHandler', () => {
   let userRepository: UserRepositoryInterface
@@ -25,9 +23,6 @@ describe('SubscriptionExpiredEventHandler', () => {
   let user: User
   let event: SubscriptionExpiredEvent
   let timestamp: number
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-  let statisticsStore: StatisticsStoreInterface
 
   const createHandler = () =>
     new SubscriptionExpiredEventHandler(
@@ -35,9 +30,6 @@ describe('SubscriptionExpiredEventHandler', () => {
       userSubscriptionRepository,
       offlineUserSubscriptionRepository,
       roleService,
-      getUserAnalyticsId,
-      analyticsStore,
-      statisticsStore,
       logger,
     )
 
@@ -82,15 +74,6 @@ describe('SubscriptionExpiredEventHandler', () => {
       totalActiveSubscriptionsCount: 123,
     }
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.setMeasure = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.info = jest.fn()
     logger.warn = jest.fn()

+ 0 - 26
packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.ts

@@ -8,14 +8,6 @@ import { RoleServiceInterface } from '../Role/RoleServiceInterface'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
-import {
-  AnalyticsStoreInterface,
-  AnalyticsActivity,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 @injectable()
 export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterface {
@@ -25,9 +17,6 @@ export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterf
     @inject(TYPES.OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
     @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -47,21 +36,6 @@ export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterf
 
     await this.updateSubscriptionEndsAt(event.payload.subscriptionId, event.payload.timestamp)
     await this.removeRoleFromSubscriptionUsers(event.payload.subscriptionId, event.payload.subscriptionName)
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity(
-      [AnalyticsActivity.SubscriptionExpired, AnalyticsActivity.ExistingCustomersChurn],
-      analyticsId,
-      [Period.Today, Period.ThisWeek, Period.ThisMonth],
-    )
-
-    const activeSubscriptions = await this.userSubscriptionRepository.countActiveSubscriptions()
-    await this.statisticsStore.setMeasure(StatisticsMeasure.TotalCustomers, activeSubscriptions, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-      Period.ThisYear,
-    ])
   }
 
   private async removeRoleFromSubscriptionUsers(

+ 0 - 57
packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts

@@ -16,10 +16,6 @@ import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/Offl
 import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription'
 import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
 import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
-import { AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
-import { AnalyticsEntity } from '../Analytics/AnalyticsEntity'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { TimerInterface } from '@standardnotes/time'
 
 describe('SubscriptionPurchasedEventHandler', () => {
   let userRepository: UserRepositoryInterface
@@ -33,11 +29,7 @@ describe('SubscriptionPurchasedEventHandler', () => {
   let event: SubscriptionPurchasedEvent
   let subscriptionExpiresAt: number
   let subscriptionSettingService: SubscriptionSettingServiceInterface
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
   let timestamp: number
-  let statisticsStore: StatisticsStoreInterface
-  let timer: TimerInterface
 
   const createHandler = () =>
     new SubscriptionPurchasedEventHandler(
@@ -46,10 +38,6 @@ describe('SubscriptionPurchasedEventHandler', () => {
       offlineUserSubscriptionRepository,
       roleService,
       subscriptionSettingService,
-      getUserAnalyticsId,
-      analyticsStore,
-      statisticsStore,
-      timer,
       logger,
     )
 
@@ -71,13 +59,6 @@ describe('SubscriptionPurchasedEventHandler', () => {
     userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
     userRepository.save = jest.fn().mockReturnValue(user)
 
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.incrementMeasure = jest.fn()
-    statisticsStore.setMeasure = jest.fn()
-
-    timer = {} as jest.Mocked<TimerInterface>
-    timer.convertDateToMicroseconds = jest.fn().mockReturnValue(1)
-
     userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
     userSubscriptionRepository.countByUserUuid = jest.fn().mockReturnValue(0)
     userSubscriptionRepository.countActiveSubscriptions = jest.fn().mockReturnValue(13)
@@ -114,13 +95,6 @@ describe('SubscriptionPurchasedEventHandler', () => {
     subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
     subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription = jest.fn()
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-    analyticsStore.unmarkActivity = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.info = jest.fn()
     logger.warn = jest.fn()
@@ -166,37 +140,6 @@ describe('SubscriptionPurchasedEventHandler', () => {
       updatedAt: expect.any(Number),
       cancelled: false,
     })
-    expect(statisticsStore.incrementMeasure).toHaveBeenCalled()
-  })
-
-  it("should not measure registration to subscription time if this is not user's first subscription", async () => {
-    userSubscriptionRepository.countByUserUuid = jest.fn().mockReturnValue(1)
-
-    await createHandler().handle(event)
-
-    expect(statisticsStore.incrementMeasure).not.toHaveBeenCalled()
-  })
-
-  it('should update analytics on limited discount offer purchasing', async () => {
-    const analyticsEntity = { id: 3 } as jest.Mocked<AnalyticsEntity>
-
-    user = {
-      uuid: '123',
-      email: 'test@test.com',
-      roles: Promise.resolve([
-        {
-          name: RoleName.CoreUser,
-        },
-      ]),
-      analyticsEntity: Promise.resolve(analyticsEntity),
-    } as jest.Mocked<User>
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
-
-    event.payload.discountCode = 'limited-10'
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith(['limited-discount-offer-purchased'], 3, [Period.Today])
   })
 
   it('should create an offline subscription', async () => {

+ 0 - 57
packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts

@@ -13,15 +13,6 @@ import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
 import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
 import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { TimerInterface } from '@standardnotes/time'
 
 @injectable()
 export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInterface {
@@ -32,10 +23,6 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
     @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
     @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
-    @inject(TYPES.Timer) private timer: TimerInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -61,8 +48,6 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
       return
     }
 
-    const previousSubscriptionCount = await this.userSubscriptionRepository.countByUserUuid(user.uuid)
-
     const userSubscription = await this.createSubscription(
       event.payload.subscriptionId,
       event.payload.subscriptionName,
@@ -78,48 +63,6 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
       event.payload.subscriptionName,
       user.uuid,
     )
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionPurchased], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-    await this.analyticsStore.unmarkActivity(
-      [AnalyticsActivity.ExistingCustomersChurn, AnalyticsActivity.NewCustomersChurn],
-      analyticsId,
-      [Period.Today, Period.ThisWeek, Period.ThisMonth],
-    )
-
-    const limitedDiscountPurchased = ['limited-10', 'limited-20', 'exit-20'].includes(
-      event.payload.discountCode as string,
-    )
-    if (limitedDiscountPurchased) {
-      await this.analyticsStore.markActivity([AnalyticsActivity.LimitedDiscountOfferPurchased], analyticsId, [
-        Period.Today,
-      ])
-    }
-
-    if (previousSubscriptionCount === 0) {
-      await this.statisticsStore.incrementMeasure(
-        StatisticsMeasure.RegistrationToSubscriptionTime,
-        event.payload.timestamp - this.timer.convertDateToMicroseconds(user.createdAt),
-        [Period.Today, Period.ThisWeek, Period.ThisMonth],
-      )
-      await this.statisticsStore.incrementMeasure(StatisticsMeasure.NewCustomers, 1, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-        Period.ThisYear,
-      ])
-      const activeSubscriptions = await this.userSubscriptionRepository.countActiveSubscriptions()
-      await this.statisticsStore.setMeasure(StatisticsMeasure.TotalCustomers, activeSubscriptions, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-        Period.ThisYear,
-      ])
-    }
   }
 
   private async addUserRole(user: User, subscriptionName: SubscriptionName): Promise<void> {

+ 0 - 78
packages/auth/src/Domain/Handler/SubscriptionReactivatedEventHandler.spec.ts

@@ -1,78 +0,0 @@
-import 'reflect-metadata'
-
-import { RoleName, SubscriptionName } from '@standardnotes/common'
-import { SubscriptionReactivatedEvent } from '@standardnotes/domain-events'
-import { Logger } from 'winston'
-
-import { User } from '../User/User'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-import { SubscriptionReactivatedEventHandler } from './SubscriptionReactivatedEventHandler'
-import { AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-
-describe('SubscriptionReactivatedEventHandler', () => {
-  let userRepository: UserRepositoryInterface
-  let logger: Logger
-  let user: User
-  let event: SubscriptionReactivatedEvent
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-
-  const createHandler = () =>
-    new SubscriptionReactivatedEventHandler(userRepository, analyticsStore, getUserAnalyticsId, logger)
-
-  beforeEach(() => {
-    user = {
-      uuid: '123',
-      email: 'test@test.com',
-      roles: Promise.resolve([
-        {
-          name: RoleName.ProUser,
-        },
-      ]),
-    } as jest.Mocked<User>
-
-    userRepository = {} as jest.Mocked<UserRepositoryInterface>
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
-    userRepository.save = jest.fn().mockReturnValue(user)
-
-    event = {} as jest.Mocked<SubscriptionReactivatedEvent>
-    event.createdAt = new Date(1)
-    event.payload = {
-      previousSubscriptionId: 1,
-      currentSubscriptionId: 2,
-      userEmail: 'test@test.com',
-      subscriptionName: SubscriptionName.PlusPlan,
-      subscriptionExpiresAt: 5,
-      discountCode: 'exit-20',
-    }
-
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
-    logger = {} as jest.Mocked<Logger>
-    logger.info = jest.fn()
-    logger.warn = jest.fn()
-  })
-
-  it('should mark subscription reactivated activity for analytics', async () => {
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith(['subscription-reactivated'], 3, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-  })
-
-  it('should not do anything if no user is found for specified email', async () => {
-    userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
-  })
-})

+ 0 - 34
packages/auth/src/Domain/Handler/SubscriptionReactivatedEventHandler.ts

@@ -1,34 +0,0 @@
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
-import { DomainEventHandlerInterface, SubscriptionReactivatedEvent } from '@standardnotes/domain-events'
-import { inject, injectable } from 'inversify'
-import { Logger } from 'winston'
-
-import TYPES from '../../Bootstrap/Types'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
-
-@injectable()
-export class SubscriptionReactivatedEventHandler implements DomainEventHandlerInterface {
-  constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.Logger) private logger: Logger,
-  ) {}
-
-  async handle(event: SubscriptionReactivatedEvent): Promise<void> {
-    const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
-
-    if (user === null) {
-      this.logger.warn(`Could not find user with email: ${event.payload.userEmail}`)
-      return
-    }
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionReactivated], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-  }
-}

+ 0 - 47
packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.spec.ts

@@ -13,8 +13,6 @@ import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscri
 import { RoleServiceInterface } from '../Role/RoleServiceInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
 import { UserSubscription } from '../Subscription/UserSubscription'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { AnalyticsActivity, AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
 
 describe('SubscriptionRefundedEventHandler', () => {
   let userRepository: UserRepositoryInterface
@@ -25,9 +23,6 @@ describe('SubscriptionRefundedEventHandler', () => {
   let user: User
   let event: SubscriptionRefundedEvent
   let timestamp: number
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
-  let statisticsStore: StatisticsStoreInterface
 
   const createHandler = () =>
     new SubscriptionRefundedEventHandler(
@@ -35,9 +30,6 @@ describe('SubscriptionRefundedEventHandler', () => {
       userSubscriptionRepository,
       offlineUserSubscriptionRepository,
       roleService,
-      getUserAnalyticsId,
-      analyticsStore,
-      statisticsStore,
       logger,
     )
 
@@ -84,16 +76,6 @@ describe('SubscriptionRefundedEventHandler', () => {
       totalActiveSubscriptionsCount: 1,
     }
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-    analyticsStore.wasActivityDone = jest.fn().mockReturnValue(true)
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.setMeasure = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.info = jest.fn()
     logger.warn = jest.fn()
@@ -129,33 +111,4 @@ describe('SubscriptionRefundedEventHandler', () => {
     expect(roleService.removeUserRole).not.toHaveBeenCalled()
     expect(userSubscriptionRepository.updateEndsAt).not.toHaveBeenCalled()
   })
-
-  it('should mark churn for new customer', async () => {
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith([AnalyticsActivity.NewCustomersChurn], 3, [
-      Period.ThisMonth,
-    ])
-  })
-
-  it('should mark churn for existing customer', async () => {
-    userSubscriptionRepository.countByUserUuid = jest.fn().mockReturnValue(3)
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith([AnalyticsActivity.ExistingCustomersChurn], 3, [
-      Period.ThisMonth,
-    ])
-  })
-
-  it('should not mark churn if customer did not purchase subscription in defined analytic periods', async () => {
-    userSubscriptionRepository.countByUserUuid = jest.fn().mockReturnValue(3)
-    analyticsStore.wasActivityDone = jest.fn().mockReturnValue(false)
-
-    await createHandler().handle(event)
-
-    expect(analyticsStore.markActivity).not.toHaveBeenCalledWith([AnalyticsActivity.ExistingCustomersChurn], 3, [
-      Period.ThisMonth,
-    ])
-  })
 })

+ 1 - 47
packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.ts

@@ -1,4 +1,4 @@
-import { SubscriptionName, Uuid } from '@standardnotes/common'
+import { SubscriptionName } from '@standardnotes/common'
 import { DomainEventHandlerInterface, SubscriptionRefundedEvent } from '@standardnotes/domain-events'
 import { inject, injectable } from 'inversify'
 import { Logger } from 'winston'
@@ -8,14 +8,6 @@ import { RoleServiceInterface } from '../Role/RoleServiceInterface'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
 import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 @injectable()
 export class SubscriptionRefundedEventHandler implements DomainEventHandlerInterface {
@@ -25,9 +17,6 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
     @inject(TYPES.OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
     @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -47,15 +36,6 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
 
     await this.updateSubscriptionEndsAt(event.payload.subscriptionId, event.payload.timestamp)
     await this.removeRoleFromSubscriptionUsers(event.payload.subscriptionId, event.payload.subscriptionName)
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRefunded], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-
-    await this.markChurnActivity(analyticsId, user.uuid)
   }
 
   private async removeRoleFromSubscriptionUsers(
@@ -75,30 +55,4 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
   private async updateOfflineSubscriptionEndsAt(subscriptionId: number, timestamp: number): Promise<void> {
     await this.offlineUserSubscriptionRepository.updateEndsAt(subscriptionId, timestamp, timestamp)
   }
-
-  private async markChurnActivity(analyticsId: number, userUuid: Uuid): Promise<void> {
-    const existingSubscriptionsCount = await this.userSubscriptionRepository.countByUserUuid(userUuid)
-
-    const churnActivity =
-      existingSubscriptionsCount > 1 ? AnalyticsActivity.ExistingCustomersChurn : AnalyticsActivity.NewCustomersChurn
-
-    for (const period of [Period.ThisMonth, Period.ThisWeek, Period.Today]) {
-      const customerPurchasedInPeriod = await this.analyticsStore.wasActivityDone(
-        AnalyticsActivity.SubscriptionPurchased,
-        analyticsId,
-        period,
-      )
-      if (customerPurchasedInPeriod) {
-        await this.analyticsStore.markActivity([churnActivity], analyticsId, [period])
-      }
-    }
-
-    const activeSubscriptions = await this.userSubscriptionRepository.countActiveSubscriptions()
-    await this.statisticsStore.setMeasure(StatisticsMeasure.TotalCustomers, activeSubscriptions, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-      Period.ThisYear,
-    ])
-  }
 }

+ 0 - 13
packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.spec.ts

@@ -13,8 +13,6 @@ import { UserSubscription } from '../Subscription/UserSubscription'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription'
 import { RoleServiceInterface } from '../Role/RoleServiceInterface'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { AnalyticsStoreInterface } from '@standardnotes/analytics'
 
 describe('SubscriptionRenewedEventHandler', () => {
   let userRepository: UserRepositoryInterface
@@ -28,8 +26,6 @@ describe('SubscriptionRenewedEventHandler', () => {
   let event: SubscriptionRenewedEvent
   let subscriptionExpiresAt: number
   let timestamp: number
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
 
   const createHandler = () =>
     new SubscriptionRenewedEventHandler(
@@ -37,8 +33,6 @@ describe('SubscriptionRenewedEventHandler', () => {
       userSubscriptionRepository,
       offlineUserSubscriptionRepository,
       roleService,
-      getUserAnalyticsId,
-      analyticsStore,
       logger,
     )
 
@@ -89,13 +83,6 @@ describe('SubscriptionRenewedEventHandler', () => {
       offline: false,
     }
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-    analyticsStore.unmarkActivity = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.warn = jest.fn()
   })

+ 0 - 16
packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.ts

@@ -1,6 +1,5 @@
 import { DomainEventHandlerInterface, SubscriptionRenewedEvent } from '@standardnotes/domain-events'
 import { inject, injectable } from 'inversify'
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 
 import TYPES from '../../Bootstrap/Types'
 import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
@@ -10,7 +9,6 @@ import { RoleServiceInterface } from '../Role/RoleServiceInterface'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { Logger } from 'winston'
 import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 @injectable()
 export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterface {
@@ -20,8 +18,6 @@ export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterf
     @inject(TYPES.OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
     @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -63,18 +59,6 @@ export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterf
     }
 
     await this.addRoleToSubscriptionUsers(event.payload.subscriptionId, event.payload.subscriptionName)
-
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRenewed], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-    await this.analyticsStore.unmarkActivity(
-      [AnalyticsActivity.ExistingCustomersChurn, AnalyticsActivity.NewCustomersChurn],
-      analyticsId,
-      [Period.Today, Period.ThisWeek, Period.ThisMonth],
-    )
   }
 
   private async addRoleToSubscriptionUsers(subscriptionId: number, subscriptionName: SubscriptionName): Promise<void> {

+ 2 - 26
packages/auth/src/Domain/Handler/UserRegisteredEventHandler.spec.ts

@@ -4,8 +4,6 @@ import { Logger } from 'winston'
 
 import { UserRegisteredEventHandler } from './UserRegisteredEventHandler'
 import { AxiosInstance } from 'axios'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
-import { AnalyticsStoreInterface } from '@standardnotes/analytics'
 import { ProtocolVersion } from '@standardnotes/common'
 
 describe('UserRegisteredEventHandler', () => {
@@ -13,19 +11,10 @@ describe('UserRegisteredEventHandler', () => {
   const userServerRegistrationUrl = 'https://user-server/registration'
   const userServerAuthKey = 'auth-key'
   let event: UserRegisteredEvent
-  let getUserAnalyticsId: GetUserAnalyticsId
-  let analyticsStore: AnalyticsStoreInterface
   let logger: Logger
 
   const createHandler = () =>
-    new UserRegisteredEventHandler(
-      httpClient,
-      userServerRegistrationUrl,
-      userServerAuthKey,
-      getUserAnalyticsId,
-      analyticsStore,
-      logger,
-    )
+    new UserRegisteredEventHandler(httpClient, userServerRegistrationUrl, userServerAuthKey, logger)
 
   beforeEach(() => {
     httpClient = {} as jest.Mocked<AxiosInstance>
@@ -39,12 +28,6 @@ describe('UserRegisteredEventHandler', () => {
       protocolVersion: ProtocolVersion.V004,
     }
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
-
     logger = {} as jest.Mocked<Logger>
     logger.debug = jest.fn()
   })
@@ -71,14 +54,7 @@ describe('UserRegisteredEventHandler', () => {
   })
 
   it('should not send a request to the user management server about a registration if url is not defined', async () => {
-    const handler = new UserRegisteredEventHandler(
-      httpClient,
-      '',
-      userServerAuthKey,
-      getUserAnalyticsId,
-      analyticsStore,
-      logger,
-    )
+    const handler = new UserRegisteredEventHandler(httpClient, '', userServerAuthKey, logger)
     await handler.handle(event)
 
     expect(httpClient.request).not.toHaveBeenCalled()

+ 0 - 11
packages/auth/src/Domain/Handler/UserRegisteredEventHandler.ts

@@ -1,11 +1,9 @@
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 import { DomainEventHandlerInterface, UserRegisteredEvent } from '@standardnotes/domain-events'
 import { AxiosInstance } from 'axios'
 import { inject, injectable } from 'inversify'
 import { Logger } from 'winston'
 
 import TYPES from '../../Bootstrap/Types'
-import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
 
 @injectable()
 export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
@@ -13,8 +11,6 @@ export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
     @inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
     @inject(TYPES.USER_SERVER_REGISTRATION_URL) private userServerRegistrationUrl: string,
     @inject(TYPES.USER_SERVER_AUTH_KEY) private userServerAuthKey: string,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {}
 
@@ -24,13 +20,6 @@ export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
       return
     }
 
-    const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: event.payload.userUuid })
-    await this.analyticsStore.markActivity([AnalyticsActivity.Register], analyticsId, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-
     await this.httpClient.request({
       method: 'POST',
       url: this.userServerRegistrationUrl,

+ 2 - 44
packages/auth/src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken.spec.ts

@@ -6,7 +6,6 @@ import { Session } from '../../Session/Session'
 import { User } from '../../User/User'
 import { Role } from '../../Role/Role'
 import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
-import { GetUserAnalyticsId } from '../GetUserAnalyticsId/GetUserAnalyticsId'
 
 import { CreateCrossServiceToken } from './CreateCrossServiceToken'
 
@@ -15,7 +14,6 @@ describe('CreateCrossServiceToken', () => {
   let sessionProjector: ProjectorInterface<Session>
   let roleProjector: ProjectorInterface<Role>
   let tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>
-  let getUserAnalyticsId: GetUserAnalyticsId
   let userRepository: UserRepositoryInterface
   const jwtTTL = 60
 
@@ -23,17 +21,8 @@ describe('CreateCrossServiceToken', () => {
   let user: User
   let role: Role
 
-  const createUseCase = (analyticsEnabled = true) =>
-    new CreateCrossServiceToken(
-      userProjector,
-      sessionProjector,
-      roleProjector,
-      tokenEncoder,
-      getUserAnalyticsId,
-      userRepository,
-      analyticsEnabled,
-      jwtTTL,
-    )
+  const createUseCase = () =>
+    new CreateCrossServiceToken(userProjector, sessionProjector, roleProjector, tokenEncoder, userRepository, jwtTTL)
 
   beforeEach(() => {
     session = {} as jest.Mocked<Session>
@@ -54,9 +43,6 @@ describe('CreateCrossServiceToken', () => {
     tokenEncoder = {} as jest.Mocked<TokenEncoderInterface<CrossServiceTokenData>>
     tokenEncoder.encodeExpirableToken = jest.fn().mockReturnValue('foobar')
 
-    getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
-    getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 123 })
-
     userRepository = {} as jest.Mocked<UserRepositoryInterface>
     userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
   })
@@ -67,32 +53,6 @@ describe('CreateCrossServiceToken', () => {
       session,
     })
 
-    expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
-      {
-        analyticsId: 123,
-        roles: [
-          {
-            name: 'role1',
-            uuid: '1-3-4',
-          },
-        ],
-        session: {
-          test: 'test',
-        },
-        user: {
-          bar: 'baz',
-        },
-      },
-      60,
-    )
-  })
-
-  it('should create a cross service token for user - analytics disabled', async () => {
-    await createUseCase(false).execute({
-      user,
-      session,
-    })
-
     expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
       {
         roles: [
@@ -119,7 +79,6 @@ describe('CreateCrossServiceToken', () => {
 
     expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
       {
-        analyticsId: 123,
         roles: [
           {
             name: 'role1',
@@ -141,7 +100,6 @@ describe('CreateCrossServiceToken', () => {
 
     expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
       {
-        analyticsId: 123,
         roles: [
           {
             name: 'role1',

+ 0 - 8
packages/auth/src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken.ts

@@ -8,7 +8,6 @@ import { Role } from '../../Role/Role'
 import { Session } from '../../Session/Session'
 import { User } from '../../User/User'
 import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
-import { GetUserAnalyticsId } from '../GetUserAnalyticsId/GetUserAnalyticsId'
 import { UseCaseInterface } from '../UseCaseInterface'
 import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO'
 import { CreateCrossServiceTokenResponse } from './CreateCrossServiceTokenResponse'
@@ -20,9 +19,7 @@ export class CreateCrossServiceToken implements UseCaseInterface {
     @inject(TYPES.SessionProjector) private sessionProjector: ProjectorInterface<Session>,
     @inject(TYPES.RoleProjector) private roleProjector: ProjectorInterface<Role>,
     @inject(TYPES.CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
-    @inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
     @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.ANALYTICS_ENABLED) private analyticsEnabled: boolean,
     @inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number,
   ) {}
 
@@ -43,11 +40,6 @@ export class CreateCrossServiceToken implements UseCaseInterface {
       roles: this.projectRoles(roles),
     }
 
-    if (this.analyticsEnabled) {
-      const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
-      authTokenData.analyticsId = analyticsId
-    }
-
     if (dto.session !== undefined) {
       authTokenData.session = this.projectSession(dto.session)
     }

+ 0 - 37
packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId.spec.ts

@@ -1,37 +0,0 @@
-import 'reflect-metadata'
-
-import { AnalyticsEntity } from '../../Analytics/AnalyticsEntity'
-import { AnalyticsEntityRepositoryInterface } from '../../Analytics/AnalyticsEntityRepositoryInterface'
-
-import { GetUserAnalyticsId } from './GetUserAnalyticsId'
-
-describe('GetUserAnalyticsId', () => {
-  let analyticsEntityRepository: AnalyticsEntityRepositoryInterface
-  let analyticsEntity: AnalyticsEntity
-
-  const createUseCase = () => new GetUserAnalyticsId(analyticsEntityRepository)
-
-  beforeEach(() => {
-    analyticsEntity = { id: 123 } as jest.Mocked<AnalyticsEntity>
-
-    analyticsEntityRepository = {} as jest.Mocked<AnalyticsEntityRepositoryInterface>
-    analyticsEntityRepository.findOneByUserUuid = jest.fn().mockReturnValue(analyticsEntity)
-  })
-
-  it('should return analytics id for a user', async () => {
-    expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({ analyticsId: 123 })
-  })
-
-  it('should throw error if user is missing analytics entity', async () => {
-    analyticsEntityRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
-    let error = null
-
-    try {
-      await createUseCase().execute({ userUuid: '1-2-3' })
-    } catch (caughtError) {
-      error = caughtError
-    }
-
-    expect(error).not.toBeNull()
-  })
-})

+ 0 - 25
packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId.ts

@@ -1,25 +0,0 @@
-import { inject, injectable } from 'inversify'
-import TYPES from '../../../Bootstrap/Types'
-import { AnalyticsEntityRepositoryInterface } from '../../Analytics/AnalyticsEntityRepositoryInterface'
-import { UseCaseInterface } from '../UseCaseInterface'
-import { GetUserAnalyticsIdDTO } from './GetUserAnalyticsIdDTO'
-import { GetUserAnalyticsIdResponse } from './GetUserAnalyticsIdResponse'
-
-@injectable()
-export class GetUserAnalyticsId implements UseCaseInterface {
-  constructor(
-    @inject(TYPES.AnalyticsEntityRepository) private analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
-  ) {}
-
-  async execute(dto: GetUserAnalyticsIdDTO): Promise<GetUserAnalyticsIdResponse> {
-    const analyticsEntity = await this.analyticsEntityRepository.findOneByUserUuid(dto.userUuid)
-
-    if (analyticsEntity === null) {
-      throw new Error(`Could not find analytics entity for user ${dto.userUuid}`)
-    }
-
-    return {
-      analyticsId: analyticsEntity.id,
-    }
-  }
-}

+ 0 - 5
packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsIdDTO.ts

@@ -1,5 +0,0 @@
-import { Uuid } from '@standardnotes/common'
-
-export type GetUserAnalyticsIdDTO = {
-  userUuid: Uuid
-}

+ 0 - 3
packages/auth/src/Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsIdResponse.ts

@@ -1,3 +0,0 @@
-export type GetUserAnalyticsIdResponse = {
-  analyticsId: number
-}

+ 1 - 18
packages/auth/src/Domain/UseCase/Register.spec.ts

@@ -9,7 +9,6 @@ import { User } from '../User/User'
 import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 import { Register } from './Register'
 import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
-import { AnalyticsEntityRepositoryInterface } from '../Analytics/AnalyticsEntityRepositoryInterface'
 import { AuthResponseFactory20200115 } from '../Auth/AuthResponseFactory20200115'
 
 describe('Register', () => {
@@ -20,19 +19,9 @@ describe('Register', () => {
   let user: User
   let crypter: CrypterInterface
   let timer: TimerInterface
-  let analyticsEntityRepository: AnalyticsEntityRepositoryInterface
 
   const createUseCase = () =>
-    new Register(
-      userRepository,
-      roleRepository,
-      authResponseFactory,
-      crypter,
-      false,
-      settingService,
-      timer,
-      analyticsEntityRepository,
-    )
+    new Register(userRepository, roleRepository, authResponseFactory, crypter, false, settingService, timer)
 
   beforeEach(() => {
     userRepository = {} as jest.Mocked<UserRepositoryInterface>
@@ -55,9 +44,6 @@ describe('Register', () => {
 
     timer = {} as jest.Mocked<TimerInterface>
     timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
-
-    analyticsEntityRepository = {} as jest.Mocked<AnalyticsEntityRepositoryInterface>
-    analyticsEntityRepository.save = jest.fn()
   })
 
   it('should register a new user', async () => {
@@ -91,8 +77,6 @@ describe('Register', () => {
     })
 
     expect(settingService.applyDefaultSettingsUponRegistration).toHaveBeenCalled()
-
-    expect(analyticsEntityRepository.save).toHaveBeenCalled()
   })
 
   it('should register a new user with default role', async () => {
@@ -187,7 +171,6 @@ describe('Register', () => {
         true,
         settingService,
         timer,
-        analyticsEntityRepository,
       ).execute({
         email: 'test@test.te',
         password: 'asdzxc',

+ 0 - 7
packages/auth/src/Domain/UseCase/Register.ts

@@ -14,8 +14,6 @@ import { RoleRepositoryInterface } from '../Role/RoleRepositoryInterface'
 import { CrypterInterface } from '../Encryption/CrypterInterface'
 import { TimerInterface } from '@standardnotes/time'
 import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
-import { AnalyticsEntityRepositoryInterface } from '../Analytics/AnalyticsEntityRepositoryInterface'
-import { AnalyticsEntity } from '../Analytics/AnalyticsEntity'
 import { AuthResponseFactory20200115 } from '../Auth/AuthResponseFactory20200115'
 import { AuthResponse20200115 } from '../Auth/AuthResponse20200115'
 
@@ -29,7 +27,6 @@ export class Register implements UseCaseInterface {
     @inject(TYPES.DISABLE_USER_REGISTRATION) private disableUserRegistration: boolean,
     @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
     @inject(TYPES.Timer) private timer: TimerInterface,
-    @inject(TYPES.AnalyticsEntityRepository) private analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
   ) {}
 
   async execute(dto: RegisterDTO): Promise<RegisterResponse> {
@@ -77,10 +74,6 @@ export class Register implements UseCaseInterface {
 
     await this.settingService.applyDefaultSettingsUponRegistration(user)
 
-    const analyticsEntity = new AnalyticsEntity()
-    analyticsEntity.user = Promise.resolve(user)
-    await this.analyticsEntityRepository.save(analyticsEntity)
-
     return {
       success: true,
       authResponse: (await this.authResponseFactory20200115.createResponse({

+ 1 - 12
packages/auth/src/Domain/User/User.ts

@@ -1,9 +1,8 @@
-import { Column, Entity, Index, JoinTable, ManyToMany, OneToMany, OneToOne, PrimaryGeneratedColumn } from 'typeorm'
+import { Column, Entity, Index, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn } from 'typeorm'
 import { RevokedSession } from '../Session/RevokedSession'
 import { Role } from '../Role/Role'
 import { Setting } from '../Setting/Setting'
 import { UserSubscription } from '../Subscription/UserSubscription'
-import { AnalyticsEntity } from '../Analytics/AnalyticsEntity'
 import { ProtocolVersion } from '@standardnotes/common'
 
 @Entity({ name: 'users' })
@@ -182,16 +181,6 @@ export class User {
   )
   declare subscriptions: Promise<UserSubscription[]>
 
-  @OneToOne(
-    /* istanbul ignore next */
-    () => AnalyticsEntity,
-    /* istanbul ignore next */
-    (analyticsEntity) => analyticsEntity.user,
-    /* istanbul ignore next */
-    { lazy: true, eager: false },
-  )
-  declare analyticsEntity: Promise<AnalyticsEntity>
-
   supportsSessions(): boolean {
     return parseInt(this.version) >= parseInt(ProtocolVersion.V004)
   }

+ 0 - 42
packages/auth/src/Infra/MySQL/MySQLAnalyticsEntityRepository.spec.ts

@@ -1,42 +0,0 @@
-import 'reflect-metadata'
-
-import { Repository, SelectQueryBuilder } from 'typeorm'
-
-import { AnalyticsEntity } from '../../Domain/Analytics/AnalyticsEntity'
-
-import { MySQLAnalyticsEntityRepository } from './MySQLAnalyticsEntityRepository'
-
-describe('MySQLAnalyticsEntityRepository', () => {
-  let ormRepository: Repository<AnalyticsEntity>
-  let analyticsEntity: AnalyticsEntity
-  let queryBuilder: SelectQueryBuilder<AnalyticsEntity>
-
-  const createRepository = () => new MySQLAnalyticsEntityRepository(ormRepository)
-
-  beforeEach(() => {
-    analyticsEntity = {} as jest.Mocked<AnalyticsEntity>
-
-    queryBuilder = {} as jest.Mocked<SelectQueryBuilder<AnalyticsEntity>>
-
-    ormRepository = {} as jest.Mocked<Repository<AnalyticsEntity>>
-    ormRepository.save = jest.fn()
-    ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => queryBuilder)
-  })
-
-  it('should save', async () => {
-    await createRepository().save(analyticsEntity)
-
-    expect(ormRepository.save).toHaveBeenCalledWith(analyticsEntity)
-  })
-
-  it('should find one by user uuid', async () => {
-    queryBuilder.where = jest.fn().mockReturnThis()
-    queryBuilder.getOne = jest.fn().mockReturnValue(analyticsEntity)
-
-    const result = await createRepository().findOneByUserUuid('123')
-
-    expect(queryBuilder.where).toHaveBeenCalledWith('analytics_entity.user_uuid = :userUuid', { userUuid: '123' })
-
-    expect(result).toEqual(analyticsEntity)
-  })
-})

+ 0 - 26
packages/auth/src/Infra/MySQL/MySQLAnalyticsEntityRepository.ts

@@ -1,26 +0,0 @@
-import { Uuid } from '@standardnotes/common'
-import { inject, injectable } from 'inversify'
-import { Repository } from 'typeorm'
-
-import TYPES from '../../Bootstrap/Types'
-import { AnalyticsEntity } from '../../Domain/Analytics/AnalyticsEntity'
-import { AnalyticsEntityRepositoryInterface } from '../../Domain/Analytics/AnalyticsEntityRepositoryInterface'
-
-@injectable()
-export class MySQLAnalyticsEntityRepository implements AnalyticsEntityRepositoryInterface {
-  constructor(
-    @inject(TYPES.ORMAnalyticsEntityRepository)
-    private ormRepository: Repository<AnalyticsEntity>,
-  ) {}
-
-  async findOneByUserUuid(userUuid: Uuid): Promise<AnalyticsEntity | null> {
-    return this.ormRepository
-      .createQueryBuilder('analytics_entity')
-      .where('analytics_entity.user_uuid = :userUuid', { userUuid })
-      .getOne()
-  }
-
-  async save(analyticsEntity: AnalyticsEntity): Promise<AnalyticsEntity> {
-    return this.ormRepository.save(analyticsEntity)
-  }
-}

+ 0 - 1
packages/security/src/Domain/Token/CrossServiceTokenData.ts

@@ -19,5 +19,4 @@ export type CrossServiceTokenData = {
     refresh_expiration: string
   }
   extensionKey?: string
-  analyticsId?: number
 }

+ 0 - 1
packages/syncing-server/package.json

@@ -25,7 +25,6 @@
   "dependencies": {
     "@newrelic/winston-enricher": "^4.0.0",
     "@sentry/node": "^7.3.0",
-    "@standardnotes/analytics": "workspace:*",
     "@standardnotes/common": "workspace:*",
     "@standardnotes/domain-events": "workspace:*",
     "@standardnotes/domain-events-infra": "workspace:*",

+ 0 - 14
packages/syncing-server/src/Bootstrap/Container.ts

@@ -7,13 +7,6 @@ import {
   DomainEventMessageHandlerInterface,
   DomainEventSubscriberFactoryInterface,
 } from '@standardnotes/domain-events'
-import {
-  AnalyticsStoreInterface,
-  PeriodKeyGenerator,
-  RedisAnalyticsStore,
-  RedisStatisticsStore,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
 
 import { Env } from './Env'
 import TYPES from './Types'
@@ -242,13 +235,6 @@ export class ContainerConfigLoader {
     container.bind<ExtensionsHttpServiceInterface>(TYPES.ExtensionsHttpService).to(ExtensionsHttpService)
     container.bind<ItemBackupServiceInterface>(TYPES.ItemBackupService).to(S3ItemBackupService)
     container.bind<RevisionServiceInterface>(TYPES.RevisionService).to(RevisionService)
-    const periodKeyGenerator = new PeriodKeyGenerator()
-    container
-      .bind<AnalyticsStoreInterface>(TYPES.AnalyticsStore)
-      .toConstantValue(new RedisAnalyticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
-    container
-      .bind<StatisticsStoreInterface>(TYPES.StatisticsStore)
-      .toConstantValue(new RedisStatisticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
 
     if (env.get('SNS_TOPIC_ARN', true)) {
       container

+ 0 - 2
packages/syncing-server/src/Bootstrap/Types.ts

@@ -71,8 +71,6 @@ const TYPES = {
   ContentTypeFilter: Symbol.for('ContentTypeFilter'),
   ContentFilter: Symbol.for('ContentFilter'),
   ItemFactory: Symbol.for('ItemFactory'),
-  AnalyticsStore: Symbol.for('AnalyticsStore'),
-  StatisticsStore: Symbol.for('StatisticsStore'),
   ItemTransferCalculator: Symbol.for('ItemTransferCalculator'),
 }
 

+ 0 - 5
packages/syncing-server/src/Controller/AuthMiddleware.spec.ts

@@ -50,7 +50,6 @@ describe('AuthMiddleware', () => {
             name: RoleName.ProUser,
           },
         ],
-        analyticsId: 123,
         permissions: [],
       },
       jwtSecret,
@@ -65,7 +64,6 @@ describe('AuthMiddleware', () => {
     expect(response.locals.roleNames).toEqual(['CORE_USER', 'PRO_USER'])
     expect(response.locals.session).toEqual({ uuid: '234' })
     expect(response.locals.readOnlyAccess).toBeFalsy()
-    expect(response.locals.analyticsId).toEqual(123)
     expect(response.locals.freeUser).toEqual(false)
 
     expect(next).toHaveBeenCalled()
@@ -82,7 +80,6 @@ describe('AuthMiddleware', () => {
             name: RoleName.CoreUser,
           },
         ],
-        analyticsId: 123,
         permissions: [],
       },
       jwtSecret,
@@ -116,7 +113,6 @@ describe('AuthMiddleware', () => {
             name: RoleName.ProUser,
           },
         ],
-        analyticsId: 123,
         permissions: [],
       },
       jwtSecret,
@@ -131,7 +127,6 @@ describe('AuthMiddleware', () => {
     expect(response.locals.roleNames).toEqual(['CORE_USER', 'PRO_USER'])
     expect(response.locals.session).toEqual({ uuid: '234', readonly_access: true })
     expect(response.locals.readOnlyAccess).toBeTruthy()
-    expect(response.locals.analyticsId).toEqual(123)
 
     expect(next).toHaveBeenCalled()
   })

+ 0 - 1
packages/syncing-server/src/Controller/AuthMiddleware.ts

@@ -32,7 +32,6 @@ export class AuthMiddleware extends BaseMiddleware {
         response.locals.roleNames.length === 1 && response.locals.roleNames[0] === RoleName.CoreUser
       response.locals.session = decodedToken.session
       response.locals.readOnlyAccess = decodedToken.session?.readonly_access ?? false
-      response.locals.analyticsId = decodedToken.analyticsId
 
       return next()
     } catch (error) {

+ 0 - 6
packages/syncing-server/src/Controller/ItemsController.spec.ts

@@ -74,7 +74,6 @@ describe('ItemsController', () => {
     response.locals.user = {
       uuid: '123',
     }
-    response.locals.analyticsId = 123
     response.locals.freeUser = false
 
     syncResponse = {} as jest.Mocked<SyncResponse20200115>
@@ -133,7 +132,6 @@ describe('ItemsController', () => {
         },
       ],
       userUuid: '123',
-      analyticsId: 123,
       freeUser: false,
     })
 
@@ -150,7 +148,6 @@ describe('ItemsController', () => {
     expect(checkIntegrity.execute).toHaveBeenCalledWith({
       integrityPayloads: [],
       userUuid: '123',
-      analyticsId: 123,
       freeUser: false,
     })
 
@@ -183,7 +180,6 @@ describe('ItemsController', () => {
       limit: 150,
       syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
       userUuid: '123',
-      analyticsId: 123,
       sessionUuid: null,
     })
 
@@ -215,7 +211,6 @@ describe('ItemsController', () => {
       limit: 150,
       syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
       userUuid: '123',
-      analyticsId: 123,
       sessionUuid: null,
     })
 
@@ -236,7 +231,6 @@ describe('ItemsController', () => {
       limit: 150,
       syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
       userUuid: '123',
-      analyticsId: 123,
       sessionUuid: '2-3-4',
     })
 

+ 0 - 2
packages/syncing-server/src/Controller/ItemsController.ts

@@ -41,7 +41,6 @@ export class ItemsController extends BaseHttpController {
       contentType: request.body.content_type,
       apiVersion: request.body.api ?? ApiVersion.v20161215,
       readOnlyAccess: response.locals.readOnlyAccess,
-      analyticsId: response.locals.analyticsId,
       sessionUuid: response.locals.session ? response.locals.session.uuid : null,
     })
 
@@ -62,7 +61,6 @@ export class ItemsController extends BaseHttpController {
     const result = await this.checkIntegrity.execute({
       userUuid: response.locals.user.uuid,
       integrityPayloads,
-      analyticsId: response.locals.analyticsId,
       freeUser: response.locals.freeUser,
     })
 

+ 1 - 101
packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrity.spec.ts

@@ -1,7 +1,5 @@
 import 'reflect-metadata'
 
-import { AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
-
 import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
 
 import { CheckIntegrity } from './CheckIntegrity'
@@ -9,10 +7,8 @@ import { ContentType } from '@standardnotes/common'
 
 describe('CheckIntegrity', () => {
   let itemRepository: ItemRepositoryInterface
-  let statisticsStore: StatisticsStoreInterface
-  let analyticsStore: AnalyticsStoreInterface
 
-  const createUseCase = () => new CheckIntegrity(itemRepository, statisticsStore, analyticsStore)
+  const createUseCase = () => new CheckIntegrity(itemRepository)
 
   beforeEach(() => {
     itemRepository = {} as jest.Mocked<ItemRepositoryInterface>
@@ -43,21 +39,12 @@ describe('CheckIntegrity', () => {
         content_type: ContentType.File,
       },
     ])
-
-    statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
-    statisticsStore.incrementOutOfSyncIncidents = jest.fn()
-    statisticsStore.incrementMeasure = jest.fn()
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.wasActivityDone = jest.fn().mockReturnValue(false)
-    analyticsStore.markActivity = jest.fn()
   })
 
   it('should return an empty result if there are no integrity mismatches', async () => {
     expect(
       await createUseCase().execute({
         userUuid: '1-2-3',
-        analyticsId: 1,
         freeUser: false,
         integrityPayloads: [
           {
@@ -87,7 +74,6 @@ describe('CheckIntegrity', () => {
     expect(
       await createUseCase().execute({
         userUuid: '1-2-3',
-        analyticsId: 1,
         freeUser: false,
         integrityPayloads: [
           {
@@ -116,15 +102,12 @@ describe('CheckIntegrity', () => {
         },
       ],
     })
-
-    expect(statisticsStore.incrementOutOfSyncIncidents).toHaveBeenCalled()
   })
 
   it('should return a mismatch item that is missing on the client side', async () => {
     expect(
       await createUseCase().execute({
         userUuid: '1-2-3',
-        analyticsId: 1,
         freeUser: false,
         integrityPayloads: [
           {
@@ -150,87 +133,4 @@ describe('CheckIntegrity', () => {
       ],
     })
   })
-
-  it('should count notes for statistics of free users', async () => {
-    await createUseCase().execute({
-      userUuid: '1-2-3',
-      analyticsId: 1,
-      freeUser: true,
-      integrityPayloads: [
-        {
-          uuid: '1-2-3',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '2-3-4',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '3-4-5',
-          updated_at_timestamp: 3,
-        },
-      ],
-    })
-
-    expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith('notes-count-free-users', 3, [
-      Period.Today,
-      Period.ThisMonth,
-    ])
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith(['checking-integrity'], 1, [Period.Today])
-  })
-
-  it('should count notes for statistics of paid users', async () => {
-    await createUseCase().execute({
-      userUuid: '1-2-3',
-      analyticsId: 1,
-      freeUser: false,
-      integrityPayloads: [
-        {
-          uuid: '1-2-3',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '2-3-4',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '3-4-5',
-          updated_at_timestamp: 3,
-        },
-      ],
-    })
-
-    expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith('notes-count-paid-users', 3, [
-      Period.Today,
-      Period.ThisMonth,
-    ])
-    expect(analyticsStore.markActivity).toHaveBeenCalledWith(['checking-integrity'], 1, [Period.Today])
-  })
-
-  it('should not count notes for statistics if they were already counted today', async () => {
-    analyticsStore.wasActivityDone = jest.fn().mockReturnValue(true)
-
-    await createUseCase().execute({
-      userUuid: '1-2-3',
-      analyticsId: 1,
-      freeUser: false,
-      integrityPayloads: [
-        {
-          uuid: '1-2-3',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '2-3-4',
-          updated_at_timestamp: 1,
-        },
-        {
-          uuid: '3-4-5',
-          updated_at_timestamp: 3,
-        },
-      ],
-    })
-
-    expect(statisticsStore.incrementMeasure).not.toHaveBeenCalled()
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
-  })
 })

+ 2 - 56
packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrity.ts

@@ -1,12 +1,6 @@
 import { inject, injectable } from 'inversify'
 import { IntegrityPayload } from '@standardnotes/payloads'
-import {
-  AnalyticsActivity,
-  AnalyticsStoreInterface,
-  Period,
-  StatisticsMeasure,
-  StatisticsStoreInterface,
-} from '@standardnotes/analytics'
+import { ContentType } from '@standardnotes/common'
 
 import TYPES from '../../../Bootstrap/Types'
 import { ItemRepositoryInterface } from '../../Item/ItemRepositoryInterface'
@@ -14,34 +8,19 @@ import { UseCaseInterface } from '../UseCaseInterface'
 import { CheckIntegrityDTO } from './CheckIntegrityDTO'
 import { CheckIntegrityResponse } from './CheckIntegrityResponse'
 import { ExtendedIntegrityPayload } from '../../Item/ExtendedIntegrityPayload'
-import { ContentType } from '@standardnotes/common'
 
 @injectable()
 export class CheckIntegrity implements UseCaseInterface {
-  constructor(
-    @inject(TYPES.ItemRepository) private itemRepository: ItemRepositoryInterface,
-    @inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-  ) {}
+  constructor(@inject(TYPES.ItemRepository) private itemRepository: ItemRepositoryInterface) {}
 
   async execute(dto: CheckIntegrityDTO): Promise<CheckIntegrityResponse> {
     const serverItemIntegrityPayloads = await this.itemRepository.findItemsForComputingIntegrityPayloads(dto.userUuid)
 
-    let notesCount = 0
-    let filesCount = 0
     const serverItemIntegrityPayloadsMap = new Map<string, ExtendedIntegrityPayload>()
     for (const serverItemIntegrityPayload of serverItemIntegrityPayloads) {
       serverItemIntegrityPayloadsMap.set(serverItemIntegrityPayload.uuid, serverItemIntegrityPayload)
-      if (serverItemIntegrityPayload.content_type === ContentType.Note) {
-        notesCount++
-      }
-      if (serverItemIntegrityPayload.content_type === ContentType.File) {
-        filesCount++
-      }
     }
 
-    await this.saveNotesCountStatistics(dto.freeUser, dto.analyticsId, { notes: notesCount, files: filesCount })
-
     const clientItemIntegrityPayloadsMap = new Map<string, number>()
     for (const clientItemIntegrityPayload of dto.integrityPayloads) {
       clientItemIntegrityPayloadsMap.set(
@@ -83,41 +62,8 @@ export class CheckIntegrity implements UseCaseInterface {
       }
     }
 
-    if (mismatches.length > 0) {
-      await this.statisticsStore.incrementOutOfSyncIncidents()
-    }
-
     return {
       mismatches,
     }
   }
-
-  private async saveNotesCountStatistics(
-    freeUser: boolean,
-    analyticsId: number,
-    counts: { notes: number; files: number },
-  ) {
-    const integrityWasCheckedToday = await this.analyticsStore.wasActivityDone(
-      AnalyticsActivity.CheckingIntegrity,
-      analyticsId,
-      Period.Today,
-    )
-
-    if (!integrityWasCheckedToday) {
-      await this.analyticsStore.markActivity([AnalyticsActivity.CheckingIntegrity], analyticsId, [Period.Today])
-
-      await this.statisticsStore.incrementMeasure(
-        freeUser ? StatisticsMeasure.NotesCountFreeUsers : StatisticsMeasure.NotesCountPaidUsers,
-        counts.notes,
-        [Period.Today, Period.ThisMonth],
-      )
-
-      if (!freeUser) {
-        await this.statisticsStore.incrementMeasure(StatisticsMeasure.FilesCount, counts.files, [
-          Period.Today,
-          Period.ThisMonth,
-        ])
-      }
-    }
-  }
 }

+ 0 - 1
packages/syncing-server/src/Domain/UseCase/CheckIntegrity/CheckIntegrityDTO.ts

@@ -5,5 +5,4 @@ export type CheckIntegrityDTO = {
   userUuid: Uuid
   integrityPayloads: IntegrityPayload[]
   freeUser: boolean
-  analyticsId: number
 }

+ 1 - 58
packages/syncing-server/src/Domain/UseCase/SyncItems.spec.ts

@@ -1,7 +1,6 @@
 import 'reflect-metadata'
 
 import { ContentType } from '@standardnotes/common'
-import { AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 
 import { ApiVersion } from '../Api/ApiVersion'
 import { Item } from '../Item/Item'
@@ -16,9 +15,8 @@ describe('SyncItems', () => {
   let item2: Item
   let item3: Item
   let itemHash: ItemHash
-  let analyticsStore: AnalyticsStoreInterface
 
-  const createUseCase = () => new SyncItems(itemService, analyticsStore)
+  const createUseCase = () => new SyncItems(itemService)
 
   beforeEach(() => {
     item1 = {
@@ -53,61 +51,9 @@ describe('SyncItems', () => {
       syncToken: 'qwerty',
     })
     itemService.frontLoadKeysItemsToTop = jest.fn().mockReturnValue([item3, item1])
-
-    analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
-    analyticsStore.markActivity = jest.fn()
   })
 
   it('should sync items', async () => {
-    expect(
-      await createUseCase().execute({
-        userUuid: '1-2-3',
-        itemHashes: [itemHash],
-        computeIntegrityHash: false,
-        syncToken: 'foo',
-        cursorToken: 'bar',
-        limit: 10,
-        readOnlyAccess: false,
-        contentType: 'Note',
-        apiVersion: ApiVersion.v20200115,
-        analyticsId: 123,
-        sessionUuid: '2-3-4',
-      }),
-    ).toEqual({
-      conflicts: [],
-      cursorToken: 'asdzxc',
-      retrievedItems: [item1],
-      savedItems: [item2],
-      syncToken: 'qwerty',
-    })
-
-    expect(itemService.frontLoadKeysItemsToTop).not.toHaveBeenCalled()
-    expect(itemService.getItems).toHaveBeenCalledWith({
-      contentType: 'Note',
-      cursorToken: 'bar',
-      limit: 10,
-      syncToken: 'foo',
-      userUuid: '1-2-3',
-    })
-    expect(itemService.saveItems).toHaveBeenCalledWith({
-      itemHashes: [itemHash],
-      userUuid: '1-2-3',
-      apiVersion: '20200115',
-      readOnlyAccess: false,
-      sessionUuid: '2-3-4',
-    })
-    expect(analyticsStore.markActivity).toHaveBeenNthCalledWith(1, ['editing-items'], 123, [
-      Period.Today,
-      Period.ThisWeek,
-      Period.ThisMonth,
-    ])
-    expect(analyticsStore.markActivity).toHaveBeenNthCalledWith(2, ['email-unbacked-up-data'], 123, [
-      Period.Today,
-      Period.ThisWeek,
-    ])
-  })
-
-  it('should sync items - no analytics', async () => {
     expect(
       await createUseCase().execute({
         userUuid: '1-2-3',
@@ -144,7 +90,6 @@ describe('SyncItems', () => {
       readOnlyAccess: false,
       sessionUuid: null,
     })
-    expect(analyticsStore.markActivity).not.toHaveBeenCalled()
   })
 
   it('should sync items and return items keys on top for first sync', async () => {
@@ -158,7 +103,6 @@ describe('SyncItems', () => {
         sessionUuid: '2-3-4',
         contentType: 'Note',
         apiVersion: ApiVersion.v20200115,
-        analyticsId: 123,
       }),
     ).toEqual({
       conflicts: [],
@@ -202,7 +146,6 @@ describe('SyncItems', () => {
         limit: 10,
         contentType: 'Note',
         apiVersion: ApiVersion.v20200115,
-        analyticsId: 123,
       }),
     ).toEqual({
       conflicts: [

+ 1 - 18
packages/syncing-server/src/Domain/UseCase/SyncItems.ts

@@ -1,4 +1,3 @@
-import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
 import { inject, injectable } from 'inversify'
 import TYPES from '../../Bootstrap/Types'
 import { Item } from '../Item/Item'
@@ -10,10 +9,7 @@ import { UseCaseInterface } from './UseCaseInterface'
 
 @injectable()
 export class SyncItems implements UseCaseInterface {
-  constructor(
-    @inject(TYPES.ItemService) private itemService: ItemServiceInterface,
-    @inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
-  ) {}
+  constructor(@inject(TYPES.ItemService) private itemService: ItemServiceInterface) {}
 
   async execute(dto: SyncItemsDTO): Promise<SyncItemsResponse> {
     const getItemsResult = await this.itemService.getItems({
@@ -37,19 +33,6 @@ export class SyncItems implements UseCaseInterface {
       retrievedItems = await this.itemService.frontLoadKeysItemsToTop(dto.userUuid, retrievedItems)
     }
 
-    if (dto.analyticsId && saveItemsResult.savedItems.length > 0) {
-      await this.analyticsStore.markActivity([AnalyticsActivity.EditingItems], dto.analyticsId, [
-        Period.Today,
-        Period.ThisWeek,
-        Period.ThisMonth,
-      ])
-
-      await this.analyticsStore.markActivity([AnalyticsActivity.EmailUnbackedUpData], dto.analyticsId, [
-        Period.Today,
-        Period.ThisWeek,
-      ])
-    }
-
     const syncResponse: SyncItemsResponse = {
       retrievedItems,
       syncToken: saveItemsResult.syncToken,

+ 0 - 1
packages/syncing-server/src/Domain/UseCase/SyncItemsDTO.ts

@@ -9,7 +9,6 @@ export type SyncItemsDTO = {
   syncToken?: string | null
   cursorToken?: string | null
   contentType?: string
-  analyticsId?: number
   apiVersion: string
   readOnlyAccess: boolean
   sessionUuid: Uuid | null

+ 0 - 1
yarn.lock

@@ -1899,7 +1899,6 @@ __metadata:
   dependencies:
     "@newrelic/winston-enricher": "npm:^4.0.0"
     "@sentry/node": "npm:^7.3.0"
-    "@standardnotes/analytics": "workspace:*"
     "@standardnotes/api": "npm:^1.19.0"
     "@standardnotes/common": "workspace:*"
     "@standardnotes/domain-events": "workspace:*"