From 0b82794e9c7ed82cfc08a92eafc016fbde5c4fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Thu, 13 Jul 2023 13:53:33 +0200 Subject: [PATCH] feat(auth): add overriding subscription settings on home server (#656) --- packages/auth/src/Bootstrap/Container.ts | 1 + .../Handler/FileRemovedEventHandler.spec.ts | 22 ++-- .../Domain/Handler/FileRemovedEventHandler.ts | 1 + .../Handler/FileUploadedEventHandler.spec.ts | 4 + .../Handler/FileUploadedEventHandler.ts | 12 +- .../SubscriptionPurchasedEventHandler.spec.ts | 2 - .../SubscriptionPurchasedEventHandler.ts | 6 +- ...SubscriptionReassignedEventHandler.spec.ts | 2 - .../SubscriptionReassignedEventHandler.ts | 6 +- ...scriptionSyncRequestedEventHandler.spec.ts | 2 - .../SubscriptionSyncRequestedEventHandler.ts | 6 +- .../CreateOrReplaceSubscriptionSettingDTO.ts | 2 + .../SubscriptionSettingService.spec.ts | 112 ++++++++++++------ .../Setting/SubscriptionSettingService.ts | 29 +++-- .../SubscriptionSettingServiceInterface.ts | 3 +- ...tionSettingsAssociationServiceInterface.ts | 2 +- ...AcceptSharedSubscriptionInvitation.spec.ts | 4 - .../AcceptSharedSubscriptionInvitation.ts | 6 +- .../ActivatePremiumFeatures.spec.ts | 13 +- .../ActivatePremiumFeatures.ts | 8 ++ .../UpdateSetting/UpdateSetting.spec.ts | 2 + .../UseCase/UpdateSetting/UpdateSetting.ts | 1 + 22 files changed, 154 insertions(+), 92 deletions(-) diff --git a/packages/auth/src/Bootstrap/Container.ts b/packages/auth/src/Bootstrap/Container.ts index 254e4ec24..86e17ef98 100644 --- a/packages/auth/src/Bootstrap/Container.ts +++ b/packages/auth/src/Bootstrap/Container.ts @@ -793,6 +793,7 @@ export class ContainerConfigLoader { new ActivatePremiumFeatures( container.get(TYPES.Auth_UserRepository), container.get(TYPES.Auth_UserSubscriptionRepository), + container.get(TYPES.Auth_SubscriptionSettingService), container.get(TYPES.Auth_RoleService), container.get(TYPES.Auth_Timer), ), diff --git a/packages/auth/src/Domain/Handler/FileRemovedEventHandler.spec.ts b/packages/auth/src/Domain/Handler/FileRemovedEventHandler.spec.ts index 66d7f497c..ebdd047e1 100644 --- a/packages/auth/src/Domain/Handler/FileRemovedEventHandler.spec.ts +++ b/packages/auth/src/Domain/Handler/FileRemovedEventHandler.spec.ts @@ -13,7 +13,8 @@ import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscripti describe('FileRemovedEventHandler', () => { let userSubscriptionService: UserSubscriptionServiceInterface let logger: Logger - let user: User + let regularUser: User + let sharedUser: User let event: FileRemovedEvent let subscriptionSettingService: SubscriptionSettingServiceInterface let regularSubscription: UserSubscription @@ -22,20 +23,24 @@ describe('FileRemovedEventHandler', () => { const createHandler = () => new FileRemovedEventHandler(userSubscriptionService, subscriptionSettingService, logger) beforeEach(() => { - user = { + regularUser = { uuid: '123', } as jest.Mocked + sharedUser = { + uuid: '234', + } as jest.Mocked + regularSubscription = { uuid: '1-2-3', subscriptionType: UserSubscriptionType.Regular, - user: Promise.resolve(user), + user: Promise.resolve(regularUser), } as jest.Mocked sharedSubscription = { uuid: '2-3-4', subscriptionType: UserSubscriptionType.Shared, - user: Promise.resolve(user), + user: Promise.resolve(sharedUser), } as jest.Mocked userSubscriptionService = {} as jest.Mocked @@ -93,10 +98,11 @@ describe('FileRemovedEventHandler', () => { unencryptedValue: '222', serverEncryptionVersion: 0, }, + user: regularUser, userSubscription: { uuid: '1-2-3', subscriptionType: 'regular', - user: Promise.resolve(user), + user: Promise.resolve(regularUser), }, }) }) @@ -118,10 +124,11 @@ describe('FileRemovedEventHandler', () => { unencryptedValue: '222', serverEncryptionVersion: 0, }, + user: regularUser, userSubscription: { uuid: '1-2-3', subscriptionType: 'regular', - user: Promise.resolve(user), + user: Promise.resolve(regularUser), }, }) @@ -132,10 +139,11 @@ describe('FileRemovedEventHandler', () => { unencryptedValue: '222', serverEncryptionVersion: 0, }, + user: sharedUser, userSubscription: { uuid: '2-3-4', subscriptionType: 'shared', - user: Promise.resolve(user), + user: Promise.resolve(sharedUser), }, }) }) diff --git a/packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts b/packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts index cef93733d..5d0c185b9 100644 --- a/packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts +++ b/packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts @@ -51,6 +51,7 @@ export class FileRemovedEventHandler implements DomainEventHandlerInterface { await this.subscriptionSettingService.createOrReplace({ userSubscription: subscription, + user, props: { name: SettingName.NAMES.FileUploadBytesUsed, unencryptedValue: (+bytesUsed - byteSize).toString(), diff --git a/packages/auth/src/Domain/Handler/FileUploadedEventHandler.spec.ts b/packages/auth/src/Domain/Handler/FileUploadedEventHandler.spec.ts index 13752f260..fcefff6c1 100644 --- a/packages/auth/src/Domain/Handler/FileUploadedEventHandler.spec.ts +++ b/packages/auth/src/Domain/Handler/FileUploadedEventHandler.spec.ts @@ -76,6 +76,7 @@ describe('FileUploadedEventHandler', () => { unencryptedValue: '123', serverEncryptionVersion: 0, }, + user, userSubscription: { uuid: '1-2-3', subscriptionType: 'regular', @@ -118,6 +119,7 @@ describe('FileUploadedEventHandler', () => { unencryptedValue: '468', serverEncryptionVersion: 0, }, + user, userSubscription: { uuid: '1-2-3', subscriptionType: 'regular', @@ -143,6 +145,7 @@ describe('FileUploadedEventHandler', () => { unencryptedValue: '468', serverEncryptionVersion: 0, }, + user, userSubscription: { uuid: '1-2-3', subscriptionType: 'regular', @@ -157,6 +160,7 @@ describe('FileUploadedEventHandler', () => { unencryptedValue: '468', serverEncryptionVersion: 0, }, + user, userSubscription: { uuid: '2-3-4', subscriptionType: 'shared', diff --git a/packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts b/packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts index 80758550d..afa0209a8 100644 --- a/packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts +++ b/packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts @@ -9,6 +9,7 @@ import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSett import { UserSubscription } from '../Subscription/UserSubscription' import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscriptionServiceInterface' import { UserRepositoryInterface } from '../User/UserRepositoryInterface' +import { User } from '../User/User' @injectable() export class FileUploadedEventHandler implements DomainEventHandlerInterface { @@ -36,14 +37,18 @@ export class FileUploadedEventHandler implements DomainEventHandlerInterface { return } - await this.updateUploadBytesUsedSetting(regularSubscription, event.payload.fileByteSize) + await this.updateUploadBytesUsedSetting(regularSubscription, user, event.payload.fileByteSize) if (sharedSubscription !== null) { - await this.updateUploadBytesUsedSetting(sharedSubscription, event.payload.fileByteSize) + await this.updateUploadBytesUsedSetting(sharedSubscription, user, event.payload.fileByteSize) } } - private async updateUploadBytesUsedSetting(subscription: UserSubscription, byteSize: number): Promise { + private async updateUploadBytesUsedSetting( + subscription: UserSubscription, + user: User, + byteSize: number, + ): Promise { let bytesUsed = '0' const bytesUsedSetting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({ userUuid: (await subscription.user).uuid, @@ -56,6 +61,7 @@ export class FileUploadedEventHandler implements DomainEventHandlerInterface { await this.subscriptionSettingService.createOrReplace({ userSubscription: subscription, + user, props: { name: SettingName.NAMES.FileUploadBytesUsed, unencryptedValue: (+bytesUsed + byteSize).toString(), diff --git a/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts b/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts index 8ee45622d..43c0f9e8e 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.spec.ts @@ -114,8 +114,6 @@ describe('SubscriptionPurchasedEventHandler', () => { expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith( subscription, - SubscriptionName.ProPlan, - '123', ) }) diff --git a/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts b/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts index fb2a92727..c923c8158 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts @@ -66,11 +66,7 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte await this.addUserRole(user, event.payload.subscriptionName) - await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - event.payload.subscriptionName, - user.uuid, - ) + await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription) } private async addUserRole(user: User, subscriptionName: string): Promise { diff --git a/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.spec.ts b/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.spec.ts index 978243c4f..ac77a14cd 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.spec.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.spec.ts @@ -94,8 +94,6 @@ describe('SubscriptionReassignedEventHandler', () => { expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith( subscription, - SubscriptionName.ProPlan, - '123', ) }) diff --git a/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts b/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts index 8cb5fc3de..cfecc7615 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts @@ -63,11 +63,7 @@ export class SubscriptionReassignedEventHandler implements DomainEventHandlerInt }, }) - await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - event.payload.subscriptionName, - user.uuid, - ) + await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription) } private async addUserRole(user: User, subscriptionName: string): Promise { diff --git a/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.spec.ts b/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.spec.ts index f1a072eae..590f7369a 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.spec.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.spec.ts @@ -129,8 +129,6 @@ describe('SubscriptionSyncRequestedEventHandler', () => { expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith( subscription, - SubscriptionName.ProPlan, - '123', ) expect(settingService.createOrReplace).toHaveBeenCalledWith({ diff --git a/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts b/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts index ef7b115e5..aff013b7d 100644 --- a/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts +++ b/packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts @@ -95,11 +95,7 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler await this.roleService.addUserRole(user, event.payload.subscriptionName) - await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - event.payload.subscriptionName, - user.uuid, - ) + await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription) await this.settingService.createOrReplace({ user, diff --git a/packages/auth/src/Domain/Setting/CreateOrReplaceSubscriptionSettingDTO.ts b/packages/auth/src/Domain/Setting/CreateOrReplaceSubscriptionSettingDTO.ts index 2ea761711..b157d42a3 100644 --- a/packages/auth/src/Domain/Setting/CreateOrReplaceSubscriptionSettingDTO.ts +++ b/packages/auth/src/Domain/Setting/CreateOrReplaceSubscriptionSettingDTO.ts @@ -1,7 +1,9 @@ import { UserSubscription } from '../Subscription/UserSubscription' +import { User } from '../User/User' import { SubscriptionSettingProps } from './SubscriptionSettingProps' export type CreateOrReplaceSubscriptionSettingDTO = { userSubscription: UserSubscription + user: User props: SubscriptionSettingProps } diff --git a/packages/auth/src/Domain/Setting/SubscriptionSettingService.spec.ts b/packages/auth/src/Domain/Setting/SubscriptionSettingService.spec.ts index 8a311a074..bd6e059e5 100644 --- a/packages/auth/src/Domain/Setting/SubscriptionSettingService.spec.ts +++ b/packages/auth/src/Domain/Setting/SubscriptionSettingService.spec.ts @@ -45,6 +45,7 @@ describe('SubscriptionSettingService', () => { userSubscription = { uuid: '1-2-3', user: Promise.resolve(user), + planName: SubscriptionName.PlusPlan, } as jest.Mocked setting = { @@ -97,15 +98,70 @@ describe('SubscriptionSettingService', () => { }) it('should create default settings for a subscription', async () => { - await createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ) + await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription) expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting) }) + it('should create default settings for a subscription with overrides', async () => { + subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue( + new Map([ + [ + SettingName.NAMES.FileUploadBytesUsed, + { + value: '0', + sensitive: 0, + serverEncryptionVersion: EncryptionVersion.Unencrypted, + replaceable: false, + }, + ], + [ + SettingName.NAMES.FileUploadBytesLimit, + { + value: '345', + sensitive: 0, + serverEncryptionVersion: EncryptionVersion.Unencrypted, + replaceable: true, + }, + ], + ]), + ) + + await createService().applyDefaultSubscriptionSettingsForSubscription( + userSubscription, + new Map([[SettingName.NAMES.FileUploadBytesLimit, '123']]), + ) + + expect(factory.createSubscriptionSetting).toHaveBeenNthCalledWith( + 1, + { + name: SettingName.NAMES.FileUploadBytesUsed, + sensitive: 0, + serverEncryptionVersion: EncryptionVersion.Unencrypted, + unencryptedValue: '0', + }, + { + planName: SubscriptionName.PlusPlan, + user: Promise.resolve(user), + uuid: '1-2-3', + }, + ) + expect(factory.createSubscriptionSetting).toHaveBeenNthCalledWith( + 2, + { + name: SettingName.NAMES.FileUploadBytesLimit, + sensitive: 0, + serverEncryptionVersion: EncryptionVersion.Unencrypted, + unencryptedValue: '123', + }, + { + planName: SubscriptionName.PlusPlan, + user: Promise.resolve(user), + uuid: '1-2-3', + }, + ) + }) + it('should throw error if subscription setting is invalid', async () => { subscriptionSettingsAssociationService.getDefaultSettingsAndValuesForSubscriptionName = jest.fn().mockReturnValue( new Map([ @@ -121,13 +177,7 @@ describe('SubscriptionSettingService', () => { ]), ) - await expect( - createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ), - ).rejects.toThrow() + await expect(createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)).rejects.toThrow() }) it('should throw error if setting name is not a subscription setting when applying defaults', async () => { @@ -145,13 +195,7 @@ describe('SubscriptionSettingService', () => { ]), ) - await expect( - createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ), - ).rejects.toThrow() + await expect(createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription)).rejects.toThrow() }) it('should reassign existing default settings for a subscription if it is not replaceable', async () => { @@ -170,11 +214,7 @@ describe('SubscriptionSettingService', () => { ) subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(setting) - await createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ) + await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription) expect(subscriptionSettingRepository.save).toHaveBeenCalled() }) @@ -195,11 +235,7 @@ describe('SubscriptionSettingService', () => { ) subscriptionSettingRepository.findLastByNameAndUserSubscriptionUuid = jest.fn().mockReturnValue(null) - await createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ) + await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription) expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting) }) @@ -225,11 +261,7 @@ describe('SubscriptionSettingService', () => { } as jest.Mocked, ]) - await createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ) + await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription) expect(subscriptionSettingRepository.save).toHaveBeenCalledWith(setting) }) @@ -239,11 +271,7 @@ describe('SubscriptionSettingService', () => { .fn() .mockReturnValue(undefined) - await createService().applyDefaultSubscriptionSettingsForSubscription( - userSubscription, - SubscriptionName.PlusPlan, - '1-2-3', - ) + await createService().applyDefaultSubscriptionSettingsForSubscription(userSubscription) expect(subscriptionSettingRepository.save).not.toHaveBeenCalled() }) @@ -251,6 +279,7 @@ describe('SubscriptionSettingService', () => { it("should create setting if it doesn't exist", async () => { const result = await createService().createOrReplace({ userSubscription, + user, props: { name: SettingName.NAMES.FileUploadBytesLimit, unencryptedValue: 'value', @@ -266,6 +295,7 @@ describe('SubscriptionSettingService', () => { await expect( createService().createOrReplace({ userSubscription, + user, props: { name: 'invalid', unencryptedValue: 'value', @@ -280,6 +310,7 @@ describe('SubscriptionSettingService', () => { await expect( createService().createOrReplace({ userSubscription, + user, props: { name: SettingName.NAMES.DropboxBackupFrequency, unencryptedValue: 'value', @@ -295,6 +326,7 @@ describe('SubscriptionSettingService', () => { const result = await createService().createOrReplace({ userSubscription, + user, props: { uuid: '1-2-3', name: SettingName.NAMES.FileUploadBytesLimit, @@ -312,6 +344,7 @@ describe('SubscriptionSettingService', () => { const result = await createService().createOrReplace({ userSubscription, + user, props: { ...setting, unencryptedValue: 'value', @@ -327,6 +360,7 @@ describe('SubscriptionSettingService', () => { const result = await createService().createOrReplace({ userSubscription, + user, props: { ...setting, uuid: '1-2-3', diff --git a/packages/auth/src/Domain/Setting/SubscriptionSettingService.ts b/packages/auth/src/Domain/Setting/SubscriptionSettingService.ts index c379ae640..8550c974f 100644 --- a/packages/auth/src/Domain/Setting/SubscriptionSettingService.ts +++ b/packages/auth/src/Domain/Setting/SubscriptionSettingService.ts @@ -1,4 +1,3 @@ -import { SubscriptionName } from '@standardnotes/common' import { inject, injectable } from 'inversify' import { Logger } from 'winston' @@ -36,17 +35,20 @@ export class SubscriptionSettingService implements SubscriptionSettingServiceInt async applyDefaultSubscriptionSettingsForSubscription( userSubscription: UserSubscription, - subscriptionName: SubscriptionName, - userUuid: string, + overrides?: Map, ): Promise { const defaultSettingsWithValues = - await this.subscriptionSettingAssociationService.getDefaultSettingsAndValuesForSubscriptionName(subscriptionName) + await this.subscriptionSettingAssociationService.getDefaultSettingsAndValuesForSubscriptionName( + userSubscription.planName, + ) if (defaultSettingsWithValues === undefined) { - this.logger.warn(`Could not find settings for subscription: ${subscriptionName}`) + this.logger.warn(`Could not find settings for subscription: ${userSubscription.planName}`) return } + const user = await userSubscription.user + for (const settingNameString of defaultSettingsWithValues.keys()) { const settingNameOrError = SettingName.create(settingNameString) if (settingNameOrError.isFailed()) { @@ -59,7 +61,11 @@ export class SubscriptionSettingService implements SubscriptionSettingServiceInt const setting = defaultSettingsWithValues.get(settingName.value) as SettingDescription if (!setting.replaceable) { - const existingSetting = await this.findPreviousSubscriptionSetting(settingName, userSubscription.uuid, userUuid) + const existingSetting = await this.findPreviousSubscriptionSetting( + settingName, + userSubscription.uuid, + user.uuid, + ) if (existingSetting !== null) { existingSetting.userSubscription = Promise.resolve(userSubscription) await this.subscriptionSettingRepository.save(existingSetting) @@ -68,11 +74,17 @@ export class SubscriptionSettingService implements SubscriptionSettingServiceInt } } + let unencryptedValue = setting.value + if (overrides && overrides.has(settingName.value)) { + unencryptedValue = overrides.get(settingName.value) as string + } + await this.createOrReplace({ userSubscription, + user, props: { name: settingName.value, - unencryptedValue: setting.value, + unencryptedValue, serverEncryptionVersion: setting.serverEncryptionVersion, sensitive: setting.sensitive, }, @@ -109,7 +121,7 @@ export class SubscriptionSettingService implements SubscriptionSettingServiceInt async createOrReplace( dto: CreateOrReplaceSubscriptionSettingDTO, ): Promise { - const { userSubscription, props } = dto + const { userSubscription, user, props } = dto const settingNameOrError = SettingName.create(props.name) if (settingNameOrError.isFailed()) { @@ -121,7 +133,6 @@ export class SubscriptionSettingService implements SubscriptionSettingServiceInt throw new Error(`Setting ${settingName.value} is not a subscription setting`) } - const user = await userSubscription.user const existing = await this.findSubscriptionSettingWithDecryptedValue({ userUuid: user.uuid, userSubscriptionUuid: userSubscription.uuid, diff --git a/packages/auth/src/Domain/Setting/SubscriptionSettingServiceInterface.ts b/packages/auth/src/Domain/Setting/SubscriptionSettingServiceInterface.ts index 1f010d42a..a6280e97a 100644 --- a/packages/auth/src/Domain/Setting/SubscriptionSettingServiceInterface.ts +++ b/packages/auth/src/Domain/Setting/SubscriptionSettingServiceInterface.ts @@ -8,8 +8,7 @@ import { SubscriptionSetting } from './SubscriptionSetting' export interface SubscriptionSettingServiceInterface { applyDefaultSubscriptionSettingsForSubscription( userSubscription: UserSubscription, - subscriptionName: string, - userUuid: string, + overrides?: Map, ): Promise createOrReplace(dto: CreateOrReplaceSubscriptionSettingDTO): Promise findSubscriptionSettingWithDecryptedValue(dto: FindSubscriptionSettingDTO): Promise diff --git a/packages/auth/src/Domain/Setting/SubscriptionSettingsAssociationServiceInterface.ts b/packages/auth/src/Domain/Setting/SubscriptionSettingsAssociationServiceInterface.ts index e01b8ab85..bf87dfb5f 100644 --- a/packages/auth/src/Domain/Setting/SubscriptionSettingsAssociationServiceInterface.ts +++ b/packages/auth/src/Domain/Setting/SubscriptionSettingsAssociationServiceInterface.ts @@ -4,7 +4,7 @@ import { SettingDescription } from './SettingDescription' export interface SubscriptionSettingsAssociationServiceInterface { getDefaultSettingsAndValuesForSubscriptionName( - subscriptionName: SubscriptionName, + subscriptionName: string, ): Promise | undefined> getFileUploadLimit(subscriptionName: SubscriptionName): Promise } diff --git a/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.spec.ts b/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.spec.ts index 5dddaf7b6..97c185793 100644 --- a/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.spec.ts +++ b/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.spec.ts @@ -106,8 +106,6 @@ describe('AcceptSharedSubscriptionInvitation', () => { expect(roleService.addUserRole).toHaveBeenCalledWith(invitee, 'PLUS_PLAN') expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith( inviteeSubscription, - 'PLUS_PLAN', - '123', ) }) @@ -148,8 +146,6 @@ describe('AcceptSharedSubscriptionInvitation', () => { expect(roleService.addUserRole).toHaveBeenCalledWith(invitee, 'PLUS_PLAN') expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith( inviteeSubscription, - 'PLUS_PLAN', - '123', ) }) diff --git a/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.ts b/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.ts index b16d92137..67cbe9b1c 100644 --- a/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.ts +++ b/packages/auth/src/Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation.ts @@ -92,11 +92,7 @@ export class AcceptSharedSubscriptionInvitation implements UseCaseInterface { await this.addUserRole(invitee, inviterUserSubscription.planName as SubscriptionName) - await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription( - inviteeSubscription, - inviteeSubscription.planName as SubscriptionName, - invitee.uuid, - ) + await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(inviteeSubscription) return { success: true, diff --git a/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.spec.ts b/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.spec.ts index 418ad0fcf..efef1ed0d 100644 --- a/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.spec.ts +++ b/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.spec.ts @@ -5,16 +5,24 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface' import { ActivatePremiumFeatures } from './ActivatePremiumFeatures' import { User } from '../../User/User' +import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface' describe('ActivatePremiumFeatures', () => { let userRepository: UserRepositoryInterface let userSubscriptionRepository: UserSubscriptionRepositoryInterface + let subscriptionSettingsService: SubscriptionSettingServiceInterface let roleService: RoleServiceInterface let timer: TimerInterface let user: User const createUseCase = () => - new ActivatePremiumFeatures(userRepository, userSubscriptionRepository, roleService, timer) + new ActivatePremiumFeatures( + userRepository, + userSubscriptionRepository, + subscriptionSettingsService, + roleService, + timer, + ) beforeEach(() => { user = {} as jest.Mocked @@ -32,6 +40,9 @@ describe('ActivatePremiumFeatures', () => { timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789) timer.convertDateToMicroseconds = jest.fn().mockReturnValue(123456789) timer.getUTCDateNDaysAhead = jest.fn().mockReturnValue(new Date('2024-01-01T00:00:00.000Z')) + + subscriptionSettingsService = {} as jest.Mocked + subscriptionSettingsService.applyDefaultSubscriptionSettingsForSubscription = jest.fn() }) it('should return error when username is invalid', async () => { diff --git a/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.ts b/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.ts index fbb87569a..1cf802e10 100644 --- a/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.ts +++ b/packages/auth/src/Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures.ts @@ -7,11 +7,14 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface' import { UserSubscription } from '../../Subscription/UserSubscription' import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType' import { ActivatePremiumFeaturesDTO } from './ActivatePremiumFeaturesDTO' +import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface' +import { SettingName } from '@standardnotes/settings' export class ActivatePremiumFeatures implements UseCaseInterface { constructor( private userRepository: UserRepositoryInterface, private userSubscriptionRepository: UserSubscriptionRepositoryInterface, + private subscriptionSettingService: SubscriptionSettingServiceInterface, private roleService: RoleServiceInterface, private timer: TimerInterface, ) {} @@ -44,6 +47,11 @@ export class ActivatePremiumFeatures implements UseCaseInterface { await this.roleService.addUserRole(user, SubscriptionPlanName.NAMES.ProPlan) + await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription( + subscription, + new Map([[SettingName.NAMES.FileUploadBytesLimit, '0']]), + ) + return Result.ok('Premium features activated.') } } diff --git a/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.spec.ts b/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.spec.ts index 68783c7a5..75ee99fb0 100644 --- a/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.spec.ts +++ b/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.spec.ts @@ -268,6 +268,7 @@ describe('UpdateSetting', () => { serverEncryptionVersion: 1, sensitive: false, }, + user, userSubscription: regularSubscription, }) @@ -303,6 +304,7 @@ describe('UpdateSetting', () => { serverEncryptionVersion: 1, sensitive: false, }, + user, userSubscription: sharedSubscription, }) diff --git a/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.ts b/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.ts index 098f4ca76..722f8b1c6 100644 --- a/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.ts +++ b/packages/auth/src/Domain/UseCase/UpdateSetting/UpdateSetting.ts @@ -91,6 +91,7 @@ export class UpdateSetting implements UseCaseInterface { const response = await this.subscriptionSettingService.createOrReplace({ userSubscription: subscription, + user, props, })