mirror of
https://github.com/bitwarden/browser
synced 2025-12-26 05:03:33 +00:00
[AC-2156] Billing State Provider Migration (#8133)
* Added billing account profile state service
* Update usages after removing state service functions
* Added migrator
* Updated bw.ts and main.background.ts
* Removed comment
* Updated state service dependencies to include billing service
* Added missing mv3 factory and updated MainContextMenuHandler
* updated autofill service and tests
* Updated the remaining extensions usages
* Updated desktop
* Removed subjects where they weren't needed
* Refactored billing service to have a single setter to avoid unecessary emissions
* Refactored has premium guard to return an observable
* Renamed services to match ADR
f633f2cdd8/docs/architecture/clients/presentation/angular.md (abstract--default-implementations)
* Updated property names to be a smidgen more descriptive and added jsdocs
* Updated setting of canAccessPremium to automatically update when the underlying observable emits
* Fixed build error after merge conflicts
* Another build error from conflict
* Removed autofill unit test changes from conflict
* Updated login strategy to not set premium field using state service
* Updated CLI to use billing state provider
* Shortened names a bit
* Fixed build
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
ApiServiceInitOptions,
|
||||
} from "../../../platform/background/service-factories/api-service.factory";
|
||||
import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory";
|
||||
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
|
||||
import {
|
||||
CryptoServiceInitOptions,
|
||||
cryptoServiceFactory,
|
||||
@@ -119,6 +120,7 @@ export function loginStrategyServiceFactory(
|
||||
await deviceTrustCryptoServiceFactory(cache, opts),
|
||||
await authRequestServiceFactory(cache, opts),
|
||||
await globalStateProviderFactory(cache, opts),
|
||||
await billingAccountProfileStateServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
EventCollectionServiceInitOptions,
|
||||
eventCollectionServiceFactory,
|
||||
} from "../../../background/service-factories/event-collection-service.factory";
|
||||
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
|
||||
import {
|
||||
CachedServices,
|
||||
factory,
|
||||
@@ -69,6 +70,7 @@ export function autofillServiceFactory(
|
||||
await logServiceFactory(cache, opts),
|
||||
await domainSettingsServiceFactory(cache, opts),
|
||||
await userVerificationServiceFactory(cache, opts),
|
||||
await billingAccountProfileStateServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { of } from "rxjs";
|
||||
|
||||
import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@@ -18,6 +19,7 @@ describe("context-menu", () => {
|
||||
let autofillSettingsService: MockProxy<AutofillSettingsServiceAbstraction>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
|
||||
let removeAllSpy: jest.SpyInstance<void, [callback?: () => void]>;
|
||||
let createSpy: jest.SpyInstance<
|
||||
@@ -32,6 +34,7 @@ describe("context-menu", () => {
|
||||
autofillSettingsService = mock();
|
||||
i18nService = mock();
|
||||
logService = mock();
|
||||
billingAccountProfileStateService = mock();
|
||||
|
||||
removeAllSpy = jest
|
||||
.spyOn(chrome.contextMenus, "removeAll")
|
||||
@@ -50,6 +53,7 @@ describe("context-menu", () => {
|
||||
autofillSettingsService,
|
||||
i18nService,
|
||||
logService,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
autofillSettingsService.enableContextMenu$ = of(true);
|
||||
});
|
||||
@@ -66,7 +70,7 @@ describe("context-menu", () => {
|
||||
});
|
||||
|
||||
it("has menu enabled, but does not have premium", async () => {
|
||||
stateService.getCanAccessPremium.mockResolvedValue(false);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
|
||||
|
||||
const createdMenu = await sut.init();
|
||||
expect(createdMenu).toBeTruthy();
|
||||
@@ -74,7 +78,7 @@ describe("context-menu", () => {
|
||||
});
|
||||
|
||||
it("has menu enabled and has premium", async () => {
|
||||
stateService.getCanAccessPremium.mockResolvedValue(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
|
||||
const createdMenu = await sut.init();
|
||||
expect(createdMenu).toBeTruthy();
|
||||
@@ -128,7 +132,7 @@ describe("context-menu", () => {
|
||||
});
|
||||
|
||||
it("create entry for each cipher piece", async () => {
|
||||
stateService.getCanAccessPremium.mockResolvedValue(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
|
||||
await sut.loadOptions("TEST_TITLE", "1", createCipher());
|
||||
|
||||
@@ -137,7 +141,7 @@ describe("context-menu", () => {
|
||||
});
|
||||
|
||||
it("creates a login/unlock item for each context menu action option when user is not authenticated", async () => {
|
||||
stateService.getCanAccessPremium.mockResolvedValue(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
|
||||
await sut.loadOptions("TEST_TITLE", "NOOP");
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
SEPARATOR_ID,
|
||||
} from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
@@ -27,6 +28,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory";
|
||||
import { Account } from "../../models/account";
|
||||
import { billingAccountProfileStateServiceFactory } from "../../platform/background/service-factories/billing-account-profile-state-service.factory";
|
||||
import { CachedServices } from "../../platform/background/service-factories/factory-options";
|
||||
import {
|
||||
i18nServiceFactory,
|
||||
@@ -163,6 +165,7 @@ export class MainContextMenuHandler {
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private i18nService: I18nService,
|
||||
private logService: LogService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
static async mv3Create(cachedServices: CachedServices) {
|
||||
@@ -196,6 +199,7 @@ export class MainContextMenuHandler {
|
||||
await autofillSettingsServiceFactory(cachedServices, serviceOptions),
|
||||
await i18nServiceFactory(cachedServices, serviceOptions),
|
||||
await logServiceFactory(cachedServices, serviceOptions),
|
||||
await billingAccountProfileStateServiceFactory(cachedServices, serviceOptions),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -217,7 +221,10 @@ export class MainContextMenuHandler {
|
||||
|
||||
try {
|
||||
for (const options of this.initContextMenuItems) {
|
||||
if (options.checkPremiumAccess && !(await this.stateService.getCanAccessPremium())) {
|
||||
if (
|
||||
options.checkPremiumAccess &&
|
||||
!(await firstValueFrom(this.billingAccountProfileStateService.hasPremiumFromAnySource$))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -312,7 +319,9 @@ export class MainContextMenuHandler {
|
||||
await createChildItem(COPY_USERNAME_ID);
|
||||
}
|
||||
|
||||
const canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
);
|
||||
if (canAccessPremium && (!cipher || !Utils.isNullOrEmpty(cipher.login?.totp))) {
|
||||
await createChildItem(COPY_VERIFICATION_CODE_ID);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
DefaultDomainSettingsService,
|
||||
DomainSettingsService,
|
||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -72,6 +73,7 @@ describe("AutofillService", () => {
|
||||
const eventCollectionService = mock<EventCollectionService>();
|
||||
const logService = mock<LogService>();
|
||||
const userVerificationService = mock<UserVerificationService>();
|
||||
const billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
|
||||
beforeEach(() => {
|
||||
autofillService = new AutofillService(
|
||||
@@ -83,6 +85,7 @@ describe("AutofillService", () => {
|
||||
logService,
|
||||
domainSettingsService,
|
||||
userVerificationService,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
|
||||
@@ -476,6 +479,7 @@ describe("AutofillService", () => {
|
||||
|
||||
it("throws an error if an autofill did not occur for any of the passed pages", async () => {
|
||||
autofillOptions.tab.url = "https://a-different-url.com";
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
|
||||
try {
|
||||
await autofillService.doAutoFill(autofillOptions);
|
||||
@@ -487,7 +491,6 @@ describe("AutofillService", () => {
|
||||
});
|
||||
|
||||
it("will autofill login data for a page", async () => {
|
||||
jest.spyOn(stateService, "getCanAccessPremium");
|
||||
jest.spyOn(autofillService as any, "generateFillScript");
|
||||
jest.spyOn(autofillService as any, "generateLoginFillScript");
|
||||
jest.spyOn(logService, "info");
|
||||
@@ -497,8 +500,6 @@ describe("AutofillService", () => {
|
||||
const autofillResult = await autofillService.doAutoFill(autofillOptions);
|
||||
|
||||
const currentAutofillPageDetails = autofillOptions.pageDetails[0];
|
||||
expect(stateService.getCanAccessPremium).toHaveBeenCalled();
|
||||
expect(autofillService["getDefaultUriMatchStrategy"]).toHaveBeenCalled();
|
||||
expect(autofillService["generateFillScript"]).toHaveBeenCalledWith(
|
||||
currentAutofillPageDetails.details,
|
||||
{
|
||||
@@ -660,7 +661,7 @@ describe("AutofillService", () => {
|
||||
it("returns a TOTP value", async () => {
|
||||
const totpCode = "123456";
|
||||
autofillOptions.cipher.login.totp = "totp";
|
||||
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true);
|
||||
jest.spyOn(totpService, "getCode").mockResolvedValue(totpCode);
|
||||
|
||||
@@ -673,7 +674,7 @@ describe("AutofillService", () => {
|
||||
|
||||
it("does not return a TOTP value if the user does not have premium features", async () => {
|
||||
autofillOptions.cipher.login.totp = "totp";
|
||||
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(false);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
|
||||
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(true);
|
||||
|
||||
const autofillResult = await autofillService.doAutoFill(autofillOptions);
|
||||
@@ -707,7 +708,7 @@ describe("AutofillService", () => {
|
||||
it("returns a null value if the user cannot access premium and the organization does not use TOTP", async () => {
|
||||
autofillOptions.cipher.login.totp = "totp";
|
||||
autofillOptions.cipher.organizationUseTotp = false;
|
||||
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValueOnce(false);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(false);
|
||||
|
||||
const autofillResult = await autofillService.doAutoFill(autofillOptions);
|
||||
|
||||
@@ -717,13 +718,12 @@ describe("AutofillService", () => {
|
||||
it("returns a null value if the user has disabled `auto TOTP copy`", async () => {
|
||||
autofillOptions.cipher.login.totp = "totp";
|
||||
autofillOptions.cipher.organizationUseTotp = true;
|
||||
jest.spyOn(stateService, "getCanAccessPremium").mockResolvedValue(true);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$ = of(true);
|
||||
jest.spyOn(autofillService, "getShouldAutoCopyTotp").mockResolvedValue(false);
|
||||
jest.spyOn(totpService, "getCode");
|
||||
|
||||
const autofillResult = await autofillService.doAutoFill(autofillOptions);
|
||||
|
||||
expect(stateService.getCanAccessPremium).toHaveBeenCalled();
|
||||
expect(autofillService.getShouldAutoCopyTotp).toHaveBeenCalled();
|
||||
expect(totpService.getCode).not.toHaveBeenCalled();
|
||||
expect(autofillResult).toBeNull();
|
||||
|
||||
@@ -5,6 +5,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import {
|
||||
UriMatchStrategySetting,
|
||||
@@ -55,6 +56,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||
private logService: LogService,
|
||||
private domainSettingsService: DomainSettingsService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -240,7 +242,9 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||
|
||||
let totp: string | null = null;
|
||||
|
||||
const canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||
const canAccessPremium = await firstValueFrom(
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$,
|
||||
);
|
||||
const defaultUriMatch = await this.getDefaultUriMatchStrategy();
|
||||
|
||||
if (!canAccessPremium) {
|
||||
|
||||
@@ -64,6 +64,8 @@ import {
|
||||
UserNotificationSettingsService,
|
||||
UserNotificationSettingsServiceAbstraction,
|
||||
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.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 { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
@@ -311,6 +313,7 @@ export default class MainBackground {
|
||||
biometricStateService: BiometricStateService;
|
||||
stateEventRunnerService: StateEventRunnerService;
|
||||
ssoLoginService: SsoLoginServiceAbstraction;
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService;
|
||||
|
||||
onUpdatedRan: boolean;
|
||||
onReplacedRan: boolean;
|
||||
@@ -572,6 +575,10 @@ export default class MainBackground {
|
||||
this.stateService,
|
||||
);
|
||||
|
||||
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
||||
this.activeUserStateProvider,
|
||||
);
|
||||
|
||||
this.loginStrategyService = new LoginStrategyService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
@@ -591,6 +598,7 @@ export default class MainBackground {
|
||||
this.deviceTrustCryptoService,
|
||||
this.authRequestService,
|
||||
this.globalStateProvider,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
this.ssoLoginService = new SsoLoginService(this.stateProvider);
|
||||
@@ -718,6 +726,7 @@ export default class MainBackground {
|
||||
this.sendApiService,
|
||||
this.avatarService,
|
||||
logoutCallback,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
this.eventUploadService = new EventUploadService(
|
||||
this.apiService,
|
||||
@@ -741,6 +750,7 @@ export default class MainBackground {
|
||||
this.logService,
|
||||
this.domainSettingsService,
|
||||
this.userVerificationService,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
|
||||
|
||||
@@ -961,6 +971,7 @@ export default class MainBackground {
|
||||
this.autofillSettingsService,
|
||||
this.i18nService,
|
||||
this.logService,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
this.cipherContextMenuHandler = new CipherContextMenuHandler(
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
|
||||
|
||||
import { activeUserStateProviderFactory } from "./active-user-state-provider.factory";
|
||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||
import { StateProviderInitOptions } from "./state-provider.factory";
|
||||
|
||||
type BillingAccountProfileStateServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type BillingAccountProfileStateServiceInitOptions =
|
||||
BillingAccountProfileStateServiceFactoryOptions & StateProviderInitOptions;
|
||||
|
||||
export function billingAccountProfileStateServiceFactory(
|
||||
cache: {
|
||||
billingAccountProfileStateService?: BillingAccountProfileStateService;
|
||||
} & CachedServices,
|
||||
opts: BillingAccountProfileStateServiceInitOptions,
|
||||
): Promise<BillingAccountProfileStateService> {
|
||||
return factory(
|
||||
cache,
|
||||
"billingAccountProfileStateService",
|
||||
opts,
|
||||
async () =>
|
||||
new DefaultBillingAccountProfileStateService(
|
||||
await activeUserStateProviderFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
</header>
|
||||
<main tabindex="-1">
|
||||
<div class="content">
|
||||
<ng-container *ngIf="!isPremium">
|
||||
<ng-container *ngIf="!(isPremium$ | async)">
|
||||
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
|
||||
<p>{{ "premiumSignUpAndGet" | i18n }}</p>
|
||||
<ul class="bwi-ul">
|
||||
@@ -61,7 +61,7 @@
|
||||
></i>
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isPremium">
|
||||
<ng-container *ngIf="isPremium$ | async">
|
||||
<p class="text-center lead">{{ "premiumCurrentMember" | i18n }}</p>
|
||||
<p class="text-center">{{ "premiumCurrentMemberThanks" | i18n }}</p>
|
||||
<button type="button" class="btn block primary" (click)="manage()">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -27,6 +28,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
||||
private currencyPipe: CurrencyPipe,
|
||||
dialogService: DialogService,
|
||||
environmentService: EnvironmentService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -36,6 +38,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
||||
stateService,
|
||||
dialogService,
|
||||
environmentService,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
// Support old price string. Can be removed in future once all translations are properly updated.
|
||||
|
||||
@@ -6,6 +6,7 @@ import { first } from "rxjs/operators";
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -49,6 +50,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
||||
dialogService: DialogService,
|
||||
formBuilder: FormBuilder,
|
||||
private filePopoutUtilsService: FilePopoutUtilsService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@@ -63,6 +65,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
|
||||
sendApiService,
|
||||
dialogService,
|
||||
formBuilder,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
@@ -15,7 +16,7 @@ import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
selector: "app-action-buttons",
|
||||
templateUrl: "action-buttons.component.html",
|
||||
})
|
||||
export class ActionButtonsComponent {
|
||||
export class ActionButtonsComponent implements OnInit, OnDestroy {
|
||||
@Output() onView = new EventEmitter<CipherView>();
|
||||
@Output() launchEvent = new EventEmitter<CipherView>();
|
||||
@Input() cipher: CipherView;
|
||||
@@ -24,17 +25,28 @@ export class ActionButtonsComponent {
|
||||
cipherType = CipherType;
|
||||
userHasPremiumAccess = false;
|
||||
|
||||
private componentIsDestroyed$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private totpService: TotpService,
|
||||
private stateService: StateService,
|
||||
private passwordRepromptService: PasswordRepromptService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.userHasPremiumAccess = await this.stateService.getCanAccessPremium();
|
||||
ngOnInit() {
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$
|
||||
.pipe(takeUntil(this.componentIsDestroyed$))
|
||||
.subscribe((canAccessPremium: boolean) => {
|
||||
this.userHasPremiumAccess = canAccessPremium;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.componentIsDestroyed$.next(true);
|
||||
this.componentIsDestroyed$.complete();
|
||||
}
|
||||
|
||||
launchCipher() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { first } from "rxjs/operators";
|
||||
|
||||
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -34,6 +35,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
||||
logService: LogService,
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
@@ -46,6 +48,7 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
|
||||
stateService,
|
||||
fileDownloadService,
|
||||
dialogService,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
@@ -95,6 +96,7 @@ export class ViewComponent extends BaseViewComponent {
|
||||
fileDownloadService: FileDownloadService,
|
||||
dialogService: DialogService,
|
||||
datePipe: DatePipe,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
@@ -117,6 +119,7 @@ export class ViewComponent extends BaseViewComponent {
|
||||
fileDownloadService,
|
||||
dialogService,
|
||||
datePipe,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user