mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 14:53:33 +00:00
[PM-5568] Implement Badge Settings state provider (#8112)
* create badge settings state provider * replace state service get/set disableBadgeCounter with badge settings service equivalent * migrate disableBadgeCounter account setting to badge settings state provider * cleanup and address PR suggestions
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import { BadgeSettingsService } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CachedServices,
|
||||||
|
factory,
|
||||||
|
FactoryOptions,
|
||||||
|
} from "../../../platform/background/service-factories/factory-options";
|
||||||
|
import {
|
||||||
|
stateProviderFactory,
|
||||||
|
StateProviderInitOptions,
|
||||||
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
|
export type BadgeSettingsServiceInitOptions = FactoryOptions & StateProviderInitOptions;
|
||||||
|
|
||||||
|
export function badgeSettingsServiceFactory(
|
||||||
|
cache: { badgeSettingsService?: BadgeSettingsService } & CachedServices,
|
||||||
|
opts: BadgeSettingsServiceInitOptions,
|
||||||
|
): Promise<BadgeSettingsService> {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"badgeSettingsService",
|
||||||
|
opts,
|
||||||
|
async () => new BadgeSettingsService(await stateProviderFactory(cache, opts)),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -49,6 +49,10 @@ import {
|
|||||||
AutofillSettingsServiceAbstraction,
|
AutofillSettingsServiceAbstraction,
|
||||||
AutofillSettingsService,
|
AutofillSettingsService,
|
||||||
} from "@bitwarden/common/autofill/services/autofill-settings.service";
|
} from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
|
import {
|
||||||
|
BadgeSettingsServiceAbstraction,
|
||||||
|
BadgeSettingsService,
|
||||||
|
} from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
@@ -243,6 +247,7 @@ export default class MainBackground {
|
|||||||
notificationsService: NotificationsServiceAbstraction;
|
notificationsService: NotificationsServiceAbstraction;
|
||||||
stateService: StateServiceAbstraction;
|
stateService: StateServiceAbstraction;
|
||||||
autofillSettingsService: AutofillSettingsServiceAbstraction;
|
autofillSettingsService: AutofillSettingsServiceAbstraction;
|
||||||
|
badgeSettingsService: BadgeSettingsServiceAbstraction;
|
||||||
systemService: SystemServiceAbstraction;
|
systemService: SystemServiceAbstraction;
|
||||||
eventCollectionService: EventCollectionServiceAbstraction;
|
eventCollectionService: EventCollectionServiceAbstraction;
|
||||||
eventUploadService: EventUploadServiceAbstraction;
|
eventUploadService: EventUploadServiceAbstraction;
|
||||||
@@ -482,6 +487,7 @@ export default class MainBackground {
|
|||||||
this.stateProvider,
|
this.stateProvider,
|
||||||
this.policyService,
|
this.policyService,
|
||||||
);
|
);
|
||||||
|
this.badgeSettingsService = new BadgeSettingsService(this.stateProvider);
|
||||||
this.policyApiService = new PolicyApiService(
|
this.policyApiService = new PolicyApiService(
|
||||||
this.policyService,
|
this.policyService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
@@ -1079,7 +1085,10 @@ export default class MainBackground {
|
|||||||
this.keyConnectorService.clear(),
|
this.keyConnectorService.clear(),
|
||||||
this.vaultFilterService.clear(),
|
this.vaultFilterService.clear(),
|
||||||
this.biometricStateService.logout(userId),
|
this.biometricStateService.logout(userId),
|
||||||
// We intentionally do not clear the autofillSettingsService
|
/* We intentionally do not clear:
|
||||||
|
* - autofillSettingsService
|
||||||
|
* - badgeSettingsService
|
||||||
|
*/
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//Needs to be checked before state is cleaned
|
//Needs to be checked before state is cleaned
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
import { BadgeSettingsService } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||||
@@ -9,9 +12,8 @@ import { ContainerService } from "@bitwarden/common/platform/services/container.
|
|||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
|
||||||
import { authServiceFactory } from "../../auth/background/service-factories/auth-service.factory";
|
import { authServiceFactory } from "../../auth/background/service-factories/auth-service.factory";
|
||||||
|
import { badgeSettingsServiceFactory } from "../../autofill/background/service_factories/badge-settings-service.factory";
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory";
|
|
||||||
import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service";
|
|
||||||
import IconDetails from "../../vault/background/models/icon-details";
|
import IconDetails from "../../vault/background/models/icon-details";
|
||||||
import { cipherServiceFactory } from "../../vault/background/service_factories/cipher-service.factory";
|
import { cipherServiceFactory } from "../../vault/background/service_factories/cipher-service.factory";
|
||||||
import { BrowserApi } from "../browser/browser-api";
|
import { BrowserApi } from "../browser/browser-api";
|
||||||
@@ -24,7 +26,7 @@ export type BadgeOptions = {
|
|||||||
|
|
||||||
export class UpdateBadge {
|
export class UpdateBadge {
|
||||||
private authService: AuthService;
|
private authService: AuthService;
|
||||||
private stateService: BrowserStateService;
|
private badgeSettingsService: BadgeSettingsService;
|
||||||
private cipherService: CipherService;
|
private cipherService: CipherService;
|
||||||
private badgeAction: typeof chrome.action | typeof chrome.browserAction;
|
private badgeAction: typeof chrome.action | typeof chrome.browserAction;
|
||||||
private sidebarAction: OperaSidebarAction | FirefoxSidebarAction;
|
private sidebarAction: OperaSidebarAction | FirefoxSidebarAction;
|
||||||
@@ -152,8 +154,8 @@ export class UpdateBadge {
|
|||||||
|
|
||||||
await this.setBadgeIcon("");
|
await this.setBadgeIcon("");
|
||||||
|
|
||||||
const disableBadgeCounter = await this.stateService.getDisableBadgeCounter();
|
const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
|
||||||
if (disableBadgeCounter) {
|
if (!enableBadgeCounter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +292,7 @@ export class UpdateBadge {
|
|||||||
systemLanguage: BrowserApi.getUILanguage(),
|
systemLanguage: BrowserApi.getUILanguage(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.stateService = await stateServiceFactory(serviceCache, opts);
|
this.badgeSettingsService = await badgeSettingsServiceFactory(serviceCache, opts);
|
||||||
this.authService = await authServiceFactory(serviceCache, opts);
|
this.authService = await authServiceFactory(serviceCache, opts);
|
||||||
this.cipherService = await cipherServiceFactory(serviceCache, opts);
|
this.cipherService = await cipherServiceFactory(serviceCache, opts);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { firstValueFrom } from "rxjs";
|
|||||||
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
|
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
|
||||||
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
|
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
@@ -20,7 +21,7 @@ import { enableAccountSwitching } from "../../platform/flags";
|
|||||||
})
|
})
|
||||||
export class OptionsComponent implements OnInit {
|
export class OptionsComponent implements OnInit {
|
||||||
enableFavicon = false;
|
enableFavicon = false;
|
||||||
enableBadgeCounter = false;
|
enableBadgeCounter = true;
|
||||||
enableAutoFillOnPageLoad = false;
|
enableAutoFillOnPageLoad = false;
|
||||||
autoFillOnPageLoadDefault = false;
|
autoFillOnPageLoadDefault = false;
|
||||||
autoFillOnPageLoadOptions: any[];
|
autoFillOnPageLoadOptions: any[];
|
||||||
@@ -47,6 +48,7 @@ export class OptionsComponent implements OnInit {
|
|||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||||
|
private badgeSettingsService: BadgeSettingsServiceAbstraction,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
private themingService: AbstractThemingService,
|
private themingService: AbstractThemingService,
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
@@ -107,7 +109,7 @@ export class OptionsComponent implements OnInit {
|
|||||||
|
|
||||||
this.enableFavicon = !this.settingsService.getDisableFavicon();
|
this.enableFavicon = !this.settingsService.getDisableFavicon();
|
||||||
|
|
||||||
this.enableBadgeCounter = !(await this.stateService.getDisableBadgeCounter());
|
this.enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
|
||||||
|
|
||||||
this.enablePasskeys = await firstValueFrom(this.vaultSettingsService.enablePasskeys$);
|
this.enablePasskeys = await firstValueFrom(this.vaultSettingsService.enablePasskeys$);
|
||||||
|
|
||||||
@@ -155,7 +157,7 @@ export class OptionsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateBadgeCounter() {
|
async updateBadgeCounter() {
|
||||||
await this.stateService.setDisableBadgeCounter(!this.enableBadgeCounter);
|
await this.badgeSettingsService.setEnableBadgeCounter(this.enableBadgeCounter);
|
||||||
this.messagingService.send("bgUpdateContextMenu");
|
this.messagingService.send("bgUpdateContextMenu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ import {
|
|||||||
AutofillSettingsServiceAbstraction,
|
AutofillSettingsServiceAbstraction,
|
||||||
AutofillSettingsService,
|
AutofillSettingsService,
|
||||||
} from "@bitwarden/common/autofill/services/autofill-settings.service";
|
} from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
|
import {
|
||||||
|
BadgeSettingsServiceAbstraction,
|
||||||
|
BadgeSettingsService,
|
||||||
|
} from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction";
|
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction";
|
||||||
import { BillingBannerServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-banner.service.abstraction";
|
import { BillingBannerServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-banner.service.abstraction";
|
||||||
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
||||||
@@ -936,6 +940,11 @@ import { ModalService } from "./modal.service";
|
|||||||
useClass: AutofillSettingsService,
|
useClass: AutofillSettingsService,
|
||||||
deps: [StateProvider, PolicyServiceAbstraction],
|
deps: [StateProvider, PolicyServiceAbstraction],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: BadgeSettingsServiceAbstraction,
|
||||||
|
useClass: BadgeSettingsService,
|
||||||
|
deps: [StateProvider],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: BiometricStateService,
|
provide: BiometricStateService,
|
||||||
useClass: DefaultBiometricStateService,
|
useClass: DefaultBiometricStateService,
|
||||||
|
|||||||
31
libs/common/src/autofill/services/badge-settings.service.ts
Normal file
31
libs/common/src/autofill/services/badge-settings.service.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { map, Observable } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
BADGE_SETTINGS_DISK,
|
||||||
|
ActiveUserState,
|
||||||
|
KeyDefinition,
|
||||||
|
StateProvider,
|
||||||
|
} from "../../platform/state";
|
||||||
|
|
||||||
|
const ENABLE_BADGE_COUNTER = new KeyDefinition(BADGE_SETTINGS_DISK, "enableBadgeCounter", {
|
||||||
|
deserializer: (value: boolean) => value ?? true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export abstract class BadgeSettingsServiceAbstraction {
|
||||||
|
enableBadgeCounter$: Observable<boolean>;
|
||||||
|
setEnableBadgeCounter: (newValue: boolean) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BadgeSettingsService implements BadgeSettingsServiceAbstraction {
|
||||||
|
private enableBadgeCounterState: ActiveUserState<boolean>;
|
||||||
|
readonly enableBadgeCounter$: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor(private stateProvider: StateProvider) {
|
||||||
|
this.enableBadgeCounterState = this.stateProvider.getActive(ENABLE_BADGE_COUNTER);
|
||||||
|
this.enableBadgeCounter$ = this.enableBadgeCounterState.state$.pipe(map((x) => x ?? true));
|
||||||
|
}
|
||||||
|
|
||||||
|
async setEnableBadgeCounter(newValue: boolean): Promise<void> {
|
||||||
|
await this.enableBadgeCounterState.update(() => newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,8 +204,6 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableAddLoginNotification: (options?: StorageOptions) => Promise<boolean>;
|
getDisableAddLoginNotification: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableAddLoginNotification: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableAddLoginNotification: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableBadgeCounter: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDisableBadgeCounter: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getDisableChangedPasswordNotification: (options?: StorageOptions) => Promise<boolean>;
|
getDisableChangedPasswordNotification: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableChangedPasswordNotification: (
|
setDisableChangedPasswordNotification: (
|
||||||
value: boolean,
|
value: boolean,
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ export class AccountSettings {
|
|||||||
autoConfirmFingerPrints?: boolean;
|
autoConfirmFingerPrints?: boolean;
|
||||||
biometricUnlock?: boolean;
|
biometricUnlock?: boolean;
|
||||||
defaultUriMatch?: UriMatchType;
|
defaultUriMatch?: UriMatchType;
|
||||||
disableBadgeCounter?: boolean;
|
|
||||||
disableGa?: boolean;
|
disableGa?: boolean;
|
||||||
dontShowCardsCurrentTab?: boolean;
|
dontShowCardsCurrentTab?: boolean;
|
||||||
dontShowIdentitiesCurrentTab?: boolean;
|
dontShowIdentitiesCurrentTab?: boolean;
|
||||||
|
|||||||
@@ -889,24 +889,6 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDisableBadgeCounter(options?: StorageOptions): Promise<boolean> {
|
|
||||||
return (
|
|
||||||
(await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
|
||||||
?.settings?.disableBadgeCounter ?? false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setDisableBadgeCounter(value: boolean, options?: StorageOptions): Promise<void> {
|
|
||||||
const account = await this.getAccount(
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
account.settings.disableBadgeCounter = value;
|
|
||||||
await this.saveAccount(
|
|
||||||
account,
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDisableChangedPasswordNotification(options?: StorageOptions): Promise<boolean> {
|
async getDisableChangedPasswordNotification(options?: StorageOptions): Promise<boolean> {
|
||||||
return (
|
return (
|
||||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ export const VAULT_SETTINGS_DISK = new StateDefinition("vaultSettings", "disk",
|
|||||||
export const COLLECTION_DATA = new StateDefinition("collection", "disk", {
|
export const COLLECTION_DATA = new StateDefinition("collection", "disk", {
|
||||||
web: "memory",
|
web: "memory",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const BADGE_SETTINGS_DISK = new StateDefinition("badgeSettings", "disk");
|
||||||
|
|
||||||
export const AUTOFILL_SETTINGS_DISK = new StateDefinition("autofillSettings", "disk");
|
export const AUTOFILL_SETTINGS_DISK = new StateDefinition("autofillSettings", "disk");
|
||||||
export const AUTOFILL_SETTINGS_DISK_LOCAL = new StateDefinition("autofillSettingsLocal", "disk", {
|
export const AUTOFILL_SETTINGS_DISK_LOCAL = new StateDefinition("autofillSettingsLocal", "disk", {
|
||||||
web: "disk-local",
|
web: "disk-local",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { CollapsedGroupingsMigrator } from "./migrations/22-move-collapsed-group
|
|||||||
import { MoveBiometricPromptsToStateProviders } from "./migrations/23-move-biometric-prompts-to-state-providers";
|
import { MoveBiometricPromptsToStateProviders } from "./migrations/23-move-biometric-prompts-to-state-providers";
|
||||||
import { SmOnboardingTasksMigrator } from "./migrations/24-move-sm-onboarding-key-to-state-providers";
|
import { SmOnboardingTasksMigrator } from "./migrations/24-move-sm-onboarding-key-to-state-providers";
|
||||||
import { ClearClipboardDelayMigrator } from "./migrations/25-move-clear-clipboard-to-autofill-settings-state-provider";
|
import { ClearClipboardDelayMigrator } from "./migrations/25-move-clear-clipboard-to-autofill-settings-state-provider";
|
||||||
|
import { BadgeSettingsMigrator } from "./migrations/26-move-badge-settings-to-state-providers";
|
||||||
import { FixPremiumMigrator } from "./migrations/3-fix-premium";
|
import { FixPremiumMigrator } from "./migrations/3-fix-premium";
|
||||||
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
||||||
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
||||||
@@ -30,7 +31,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
|||||||
import { MinVersionMigrator } from "./migrations/min-version";
|
import { MinVersionMigrator } from "./migrations/min-version";
|
||||||
|
|
||||||
export const MIN_VERSION = 2;
|
export const MIN_VERSION = 2;
|
||||||
export const CURRENT_VERSION = 25;
|
export const CURRENT_VERSION = 26;
|
||||||
export type MinVersion = typeof MIN_VERSION;
|
export type MinVersion = typeof MIN_VERSION;
|
||||||
|
|
||||||
export function createMigrationBuilder() {
|
export function createMigrationBuilder() {
|
||||||
@@ -58,7 +59,8 @@ export function createMigrationBuilder() {
|
|||||||
.with(CollapsedGroupingsMigrator, 21, 22)
|
.with(CollapsedGroupingsMigrator, 21, 22)
|
||||||
.with(MoveBiometricPromptsToStateProviders, 22, 23)
|
.with(MoveBiometricPromptsToStateProviders, 22, 23)
|
||||||
.with(SmOnboardingTasksMigrator, 23, 24)
|
.with(SmOnboardingTasksMigrator, 23, 24)
|
||||||
.with(ClearClipboardDelayMigrator, 24, CURRENT_VERSION);
|
.with(ClearClipboardDelayMigrator, 24, 25)
|
||||||
|
.with(BadgeSettingsMigrator, 25, CURRENT_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function currentVersion(
|
export async function currentVersion(
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const autofillSettingsStateDefinition: {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("ProviderKeysMigrator", () => {
|
describe("AutofillSettingsKeyMigrator", () => {
|
||||||
let helper: MockProxy<MigrationHelper>;
|
let helper: MockProxy<MigrationHelper>;
|
||||||
let sut: AutofillSettingsKeyMigrator;
|
let sut: AutofillSettingsKeyMigrator;
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const autofillSettingsLocalStateDefinition: {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("ProviderKeysMigrator", () => {
|
describe("ClearClipboardDelayMigrator", () => {
|
||||||
let helper: MockProxy<MigrationHelper>;
|
let helper: MockProxy<MigrationHelper>;
|
||||||
let sut: ClearClipboardDelayMigrator;
|
let sut: ClearClipboardDelayMigrator;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import { any, MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
|
import { StateDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||||
|
import { mockMigrationHelper } from "../migration-helper.spec";
|
||||||
|
|
||||||
|
import { BadgeSettingsMigrator } from "./26-move-badge-settings-to-state-providers";
|
||||||
|
|
||||||
|
function exampleJSON() {
|
||||||
|
return {
|
||||||
|
global: {
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
},
|
||||||
|
authenticatedAccounts: ["user-1", "user-2", "user-3"],
|
||||||
|
"user-1": {
|
||||||
|
settings: {
|
||||||
|
disableBadgeCounter: true,
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff3",
|
||||||
|
},
|
||||||
|
"user-2": {
|
||||||
|
settings: {
|
||||||
|
disableBadgeCounter: false,
|
||||||
|
otherStuff: "otherStuff4",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff5",
|
||||||
|
},
|
||||||
|
"user-3": {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff6",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff7",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function rollbackJSON() {
|
||||||
|
return {
|
||||||
|
"user_user-1_badgeSettings_enableBadgeCounter": false,
|
||||||
|
"user_user-2_badgeSettings_enableBadgeCounter": true,
|
||||||
|
global: {
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
},
|
||||||
|
authenticatedAccounts: ["user-1", "user-2", "user-3"],
|
||||||
|
"user-1": {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff3",
|
||||||
|
},
|
||||||
|
"user-2": {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff4",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff5",
|
||||||
|
},
|
||||||
|
"user-3": {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff6",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff7",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const badgeSettingsStateDefinition: {
|
||||||
|
stateDefinition: StateDefinitionLike;
|
||||||
|
} = {
|
||||||
|
stateDefinition: {
|
||||||
|
name: "badgeSettings",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("BadgeSettingsMigrator", () => {
|
||||||
|
let helper: MockProxy<MigrationHelper>;
|
||||||
|
let sut: BadgeSettingsMigrator;
|
||||||
|
|
||||||
|
describe("migrate", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
helper = mockMigrationHelper(exampleJSON(), 25);
|
||||||
|
sut = new BadgeSettingsMigrator(25, 26);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove disableBadgeCounter setting from all accounts", async () => {
|
||||||
|
await sut.migrate(helper);
|
||||||
|
expect(helper.set).toHaveBeenCalledTimes(2);
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff3",
|
||||||
|
});
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("user-2", {
|
||||||
|
settings: {
|
||||||
|
otherStuff: "otherStuff4",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff5",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set badge setting values for each account", async () => {
|
||||||
|
await sut.migrate(helper);
|
||||||
|
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledTimes(2);
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||||
|
"user-1",
|
||||||
|
{ ...badgeSettingsStateDefinition, key: "enableBadgeCounter" },
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||||
|
"user-2",
|
||||||
|
{ ...badgeSettingsStateDefinition, key: "enableBadgeCounter" },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("rollback", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
helper = mockMigrationHelper(rollbackJSON(), 24);
|
||||||
|
sut = new BadgeSettingsMigrator(25, 26);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should null out new values for each account", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledTimes(2);
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||||
|
"user-1",
|
||||||
|
{ ...badgeSettingsStateDefinition, key: "enableBadgeCounter" },
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||||
|
"user-2",
|
||||||
|
{ ...badgeSettingsStateDefinition, key: "enableBadgeCounter" },
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add explicit value back to accounts", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.set).toHaveBeenCalledTimes(2);
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||||
|
settings: {
|
||||||
|
disableBadgeCounter: true,
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff3",
|
||||||
|
});
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("user-2", {
|
||||||
|
settings: {
|
||||||
|
disableBadgeCounter: false,
|
||||||
|
otherStuff: "otherStuff4",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff5",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not try to restore values to missing accounts", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.set).not.toHaveBeenCalledWith("user-3", any());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||||
|
import { Migrator } from "../migrator";
|
||||||
|
|
||||||
|
type ExpectedAccountState = {
|
||||||
|
settings?: {
|
||||||
|
disableBadgeCounter?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const enableBadgeCounterKeyDefinition: KeyDefinitionLike = {
|
||||||
|
stateDefinition: {
|
||||||
|
name: "badgeSettings",
|
||||||
|
},
|
||||||
|
key: "enableBadgeCounter",
|
||||||
|
};
|
||||||
|
|
||||||
|
export class BadgeSettingsMigrator extends Migrator<25, 26> {
|
||||||
|
async migrate(helper: MigrationHelper): Promise<void> {
|
||||||
|
// account state (e.g. account settings -> state provider framework keys)
|
||||||
|
const accounts = await helper.getAccounts<ExpectedAccountState>();
|
||||||
|
|
||||||
|
await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]);
|
||||||
|
|
||||||
|
// migrate account state
|
||||||
|
async function migrateAccount(userId: string, account: ExpectedAccountState): Promise<void> {
|
||||||
|
const accountSettings = account?.settings;
|
||||||
|
|
||||||
|
if (accountSettings?.disableBadgeCounter != undefined) {
|
||||||
|
await helper.setToUser(
|
||||||
|
userId,
|
||||||
|
enableBadgeCounterKeyDefinition,
|
||||||
|
!accountSettings.disableBadgeCounter,
|
||||||
|
);
|
||||||
|
delete account.settings.disableBadgeCounter;
|
||||||
|
|
||||||
|
// update the state account settings with the migrated values deleted
|
||||||
|
await helper.set(userId, account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async rollback(helper: MigrationHelper): Promise<void> {
|
||||||
|
// account state (e.g. state provider framework keys -> account settings)
|
||||||
|
const accounts = await helper.getAccounts<ExpectedAccountState>();
|
||||||
|
|
||||||
|
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
|
||||||
|
|
||||||
|
// rollback account state
|
||||||
|
async function rollbackAccount(userId: string, account: ExpectedAccountState): Promise<void> {
|
||||||
|
let settings = account?.settings || {};
|
||||||
|
|
||||||
|
const enableBadgeCounter: boolean = await helper.getFromUser(
|
||||||
|
userId,
|
||||||
|
enableBadgeCounterKeyDefinition,
|
||||||
|
);
|
||||||
|
|
||||||
|
// update new settings and remove the account state provider framework keys for the rolled back values
|
||||||
|
if (enableBadgeCounter != undefined) {
|
||||||
|
settings = { ...settings, disableBadgeCounter: !enableBadgeCounter };
|
||||||
|
|
||||||
|
await helper.setToUser(userId, enableBadgeCounterKeyDefinition, null);
|
||||||
|
|
||||||
|
// commit updated settings to state
|
||||||
|
await helper.set(userId, {
|
||||||
|
...account,
|
||||||
|
settings,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user