mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
[AC-1081] Merge feature/billing-obfuscation (#5172)
* [AC-431] Add new organization invite process (#4841) * [AC-431] Added properties 'key' and 'keys' to OrganizationUserAcceptRequest * [AC-431] On organization accept added check for 'initOrganization' flag and send encrypt keys if true * [AC-431] Reverted changes on AcceptOrganizationComponent and OrganizationUserAcceptRequest * [AC-431] Created OrganizationUserAcceptInitRequest * [AC-431] Added method postOrganizationUserAcceptInit to OrganizationUserService * [AC-431] Created AcceptInitOrganizationComponent and added routing config. Added 'inviteInitAcceptedDesc' to messages * [AC-431] Remove blank line * [AC-431] Remove requirement for logging in again * [AC-431] Removed accept-init-organization.component.html * Update libs/common/src/abstractions/organization-user/organization-user.service.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [AC-431] Sending collection name when initializing an org * [AC-431] Deleted component accept-init-organization and incorporated logic into accept-organization * Update libs/common/src/abstractions/organization-user/organization-user.service.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [AC-431] Returning promise chains * [AC-431] Moved ReAuth check to org accept only * [AC-431] Fixed import issues --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [AC-434] Hide billing screen for reseller clients (#4955) * [AC-434] Retrieving ProviderType for each Org * [AC-434] Hide subscription details if user cannot manage billing * [AC-434] Renamed providerType to provider-type * [AC-434] Reverted change that showed Billing History and Payment Methods tabs * [AC-434] Hiding Secrets Manager enroll * [AC-434] Renamed Billing access variables to be more readable * Apply suggestions from code review Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [AC-434] Reduce duplication in permission code * [AC-434] npm prettier * [AC-434] Changed selfhost subscription permission * [AC-434] Added canEditSubscription check for change plan buttons * [AC-434] Removed message displaying provider name in subscription * [AC-434] canEditSubscription logic depends on canViewSubscription * [AC-434] Hiding next charge value for users without billing edit permission * [AC-434] Changed canViewSubscription and canEditSubscription to be clearer * [AC-434] Altered BillingSubscriptionItemResponse.amount and BillingSubscriptionUpcomingInvoiceResponse.amount to nullable * [AC-434] Reverted change on BillingSubscriptionItemResponse.amount --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * Updated IsPaidOrgGuard reference from org.CanManageBilling to canEditSubscription --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
This commit is contained in:
parent
b3d4d9898e
commit
e3f31ac741
@ -27,7 +27,7 @@ export class IsPaidOrgGuard implements CanActivate {
|
|||||||
|
|
||||||
if (org.isFreeOrg) {
|
if (org.isFreeOrg) {
|
||||||
// Users without billing permission can't access billing
|
// Users without billing permission can't access billing
|
||||||
if (!org.canManageBilling) {
|
if (!org.canEditSubscription) {
|
||||||
await this.platformUtilsService.showDialog(
|
await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("notAvailableForFreeOrganization"),
|
this.i18nService.t("notAvailableForFreeOrganization"),
|
||||||
this.i18nService.t("upgradeOrganization"),
|
this.i18nService.t("upgradeOrganization"),
|
||||||
|
@ -151,7 +151,7 @@ export class CollectionsComponent implements OnInit {
|
|||||||
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
||||||
title: this.i18nService.t("upgradeOrganization"),
|
title: this.i18nService.t("upgradeOrganization"),
|
||||||
content: this.i18nService.t(
|
content: this.i18nService.t(
|
||||||
this.organization.canManageBilling
|
this.organization.canEditSubscription
|
||||||
? "freeOrgMaxCollectionReachedManageBilling"
|
? "freeOrgMaxCollectionReachedManageBilling"
|
||||||
: "freeOrgMaxCollectionReachedNoManageBilling",
|
: "freeOrgMaxCollectionReachedNoManageBilling",
|
||||||
this.organization.maxCollections
|
this.organization.maxCollections
|
||||||
@ -159,7 +159,7 @@ export class CollectionsComponent implements OnInit {
|
|||||||
type: SimpleDialogType.PRIMARY,
|
type: SimpleDialogType.PRIMARY,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.organization.canManageBilling) {
|
if (this.organization.canEditSubscription) {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
||||||
} else {
|
} else {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
||||||
@ -173,7 +173,7 @@ export class CollectionsComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canManageBilling) {
|
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canEditSubscription) {
|
||||||
this.router.navigate(
|
this.router.navigate(
|
||||||
["/organizations", this.organization.id, "billing", "subscription"],
|
["/organizations", this.organization.id, "billing", "subscription"],
|
||||||
{ queryParams: { upgrade: true } }
|
{ queryParams: { upgrade: true } }
|
||||||
|
@ -347,7 +347,7 @@ export class PeopleComponent
|
|||||||
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
||||||
title: this.i18nService.t("upgradeOrganization"),
|
title: this.i18nService.t("upgradeOrganization"),
|
||||||
content: this.i18nService.t(
|
content: this.i18nService.t(
|
||||||
this.organization.canManageBilling
|
this.organization.canEditSubscription
|
||||||
? "freeOrgInvLimitReachedManageBilling"
|
? "freeOrgInvLimitReachedManageBilling"
|
||||||
: "freeOrgInvLimitReachedNoManageBilling",
|
: "freeOrgInvLimitReachedNoManageBilling",
|
||||||
this.organization.seats
|
this.organization.seats
|
||||||
@ -355,7 +355,7 @@ export class PeopleComponent
|
|||||||
type: SimpleDialogType.PRIMARY,
|
type: SimpleDialogType.PRIMARY,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.organization.canManageBilling) {
|
if (this.organization.canEditSubscription) {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
||||||
} else {
|
} else {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
||||||
@ -369,7 +369,7 @@ export class PeopleComponent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canManageBilling) {
|
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canEditSubscription) {
|
||||||
this.router.navigate(["/organizations", this.organization.id, "billing", "subscription"], {
|
this.router.navigate(["/organizations", this.organization.id, "billing", "subscription"], {
|
||||||
queryParams: { upgrade: true },
|
queryParams: { upgrade: true },
|
||||||
});
|
});
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
name="BillingEmail"
|
name="BillingEmail"
|
||||||
[(ngModel)]="org.billingEmail"
|
[(ngModel)]="org.billingEmail"
|
||||||
[disabled]="selfHosted || !canManageBilling"
|
[disabled]="selfHosted || !canEditSubscription"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -48,7 +48,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
name="BusinessName"
|
name="BusinessName"
|
||||||
[(ngModel)]="org.businessName"
|
[(ngModel)]="org.businessName"
|
||||||
[disabled]="selfHosted || !canManageBilling"
|
[disabled]="selfHosted || !canEditSubscription"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,7 +33,7 @@ export class AccountComponent {
|
|||||||
rotateApiKeyModalRef: ViewContainerRef;
|
rotateApiKeyModalRef: ViewContainerRef;
|
||||||
|
|
||||||
selfHosted = false;
|
selfHosted = false;
|
||||||
canManageBilling = true;
|
canEditSubscription = true;
|
||||||
loading = true;
|
loading = true;
|
||||||
canUseApi = false;
|
canUseApi = false;
|
||||||
org: OrganizationResponse;
|
org: OrganizationResponse;
|
||||||
@ -60,7 +60,9 @@ export class AccountComponent {
|
|||||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||||
this.route.parent.parent.params.subscribe(async (params) => {
|
this.route.parent.parent.params.subscribe(async (params) => {
|
||||||
this.organizationId = params.organizationId;
|
this.organizationId = params.organizationId;
|
||||||
this.canManageBilling = this.organizationService.get(this.organizationId).canManageBilling;
|
this.canEditSubscription = this.organizationService.get(
|
||||||
|
this.organizationId
|
||||||
|
).canEditSubscription;
|
||||||
try {
|
try {
|
||||||
this.org = await this.organizationApiService.get(this.organizationId);
|
this.org = await this.organizationApiService.get(this.organizationId);
|
||||||
this.canUseApi = this.org.useApi;
|
this.canUseApi = this.org.useApi;
|
||||||
|
@ -34,7 +34,7 @@ const routes: Routes = [
|
|||||||
canActivate: [OrganizationPermissionsGuard],
|
canActivate: [OrganizationPermissionsGuard],
|
||||||
data: {
|
data: {
|
||||||
titleId: "paymentMethod",
|
titleId: "paymentMethod",
|
||||||
organizationPermissions: (org: Organization) => org.canManageBilling,
|
organizationPermissions: (org: Organization) => org.canEditPaymentMethods,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -43,7 +43,7 @@ const routes: Routes = [
|
|||||||
canActivate: [OrganizationPermissionsGuard],
|
canActivate: [OrganizationPermissionsGuard],
|
||||||
data: {
|
data: {
|
||||||
titleId: "billingHistory",
|
titleId: "billingHistory",
|
||||||
organizationPermissions: (org: Organization) => org.canManageBilling,
|
organizationPermissions: (org: Organization) => org.canViewBillingHistory,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -21,7 +21,12 @@ export class OrganizationBillingTabComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.showPaymentAndHistory$ = this.route.params.pipe(
|
this.showPaymentAndHistory$ = this.route.params.pipe(
|
||||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||||
map((org) => !this.platformUtilsService.isSelfHost() && org.canManageBilling)
|
map(
|
||||||
|
(org) =>
|
||||||
|
!this.platformUtilsService.isSelfHost() &&
|
||||||
|
org.canViewBillingHistory &&
|
||||||
|
org.canEditPaymentMethods
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<app-org-subscription-hidden
|
<app-org-subscription-hidden
|
||||||
*ngIf="firstLoaded && !userOrg.canManageBilling"
|
*ngIf="firstLoaded && !userOrg.canViewSubscription"
|
||||||
[providerName]="userOrg.providerName"
|
[providerName]="userOrg.providerName"
|
||||||
></app-org-subscription-hidden>
|
></app-org-subscription-hidden>
|
||||||
|
|
||||||
@ -64,30 +64,24 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8" *ngIf="subscription">
|
<ng-container *ngIf="userOrg.canEditSubscription">
|
||||||
<strong class="d-block mb-1">{{ "details" | i18n }}</strong>
|
<div class="col-8" *ngIf="subscription">
|
||||||
<table class="table">
|
<strong class="d-block mb-1">{{ "details" | i18n }}</strong>
|
||||||
<tbody>
|
<table class="table">
|
||||||
<tr *ngFor="let i of subscription.items">
|
<tbody>
|
||||||
<td>
|
<tr *ngFor="let i of subscription.items">
|
||||||
{{ i.name }} {{ i.quantity > 1 ? "×" + i.quantity : "" }} @
|
<td>
|
||||||
{{ i.amount | currency : "$" }}
|
{{ i.name }} {{ i.quantity > 1 ? "×" + i.quantity : "" }} @
|
||||||
</td>
|
{{ i.amount | currency : "$" }}
|
||||||
<td>{{ i.quantity * i.amount | currency : "$" }} /{{ i.interval | i18n }}</td>
|
</td>
|
||||||
</tr>
|
<td>{{ i.quantity * i.amount | currency : "$" }} /{{ i.interval | i18n }}</td>
|
||||||
</tbody>
|
</tr>
|
||||||
</table>
|
</tbody>
|
||||||
</div>
|
</table>
|
||||||
<ng-container *ngIf="userOrg?.providerId != null">
|
|
||||||
<div class="col-sm">
|
|
||||||
<dl>
|
|
||||||
<dt>{{ "provider" | i18n }}</dt>
|
|
||||||
<dd>{{ "yourProviderIs" | i18n : userOrg.providerName }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<ng-container>
|
<ng-container *ngIf="userOrg.canEditSubscription">
|
||||||
<button
|
<button
|
||||||
bitButton
|
bitButton
|
||||||
buttonType="secondary"
|
buttonType="secondary"
|
||||||
@ -105,80 +99,84 @@
|
|||||||
></app-change-plan>
|
></app-change-plan>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<sm-enroll
|
<ng-container *ngIf="userOrg.canEditSubscription">
|
||||||
*ngIf="isAdmin"
|
<sm-enroll
|
||||||
[enabled]="sub?.useSecretsManager"
|
*ngIf="isAdmin"
|
||||||
[organizationId]="organizationId"
|
[enabled]="sub?.useSecretsManager"
|
||||||
></sm-enroll>
|
[organizationId]="organizationId"
|
||||||
|
></sm-enroll>
|
||||||
<h2 class="spaced-header">{{ "manageSubscription" | i18n }}</h2>
|
|
||||||
<p class="mb-4">{{ subscriptionDesc }}</p>
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
subscription && canAdjustSeats && !subscription.cancelled && !subscriptionMarkedForCancel
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="mt-3">
|
|
||||||
<app-adjust-subscription
|
|
||||||
[seatPrice]="seatPrice"
|
|
||||||
[organizationId]="organizationId"
|
|
||||||
[interval]="billingInterval"
|
|
||||||
[currentSeatCount]="seats"
|
|
||||||
[maxAutoscaleSeats]="maxAutoscaleSeats"
|
|
||||||
(onAdjusted)="subscriptionAdjusted()"
|
|
||||||
>
|
|
||||||
</app-adjust-subscription>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<button
|
|
||||||
bitButton
|
<ng-container *ngIf="userOrg.canEditSubscription">
|
||||||
buttonType="danger"
|
<h2 class="spaced-header">{{ "manageSubscription" | i18n }}</h2>
|
||||||
type="button"
|
<p class="mb-4">{{ subscriptionDesc }}</p>
|
||||||
[bitAction]="removeSponsorship"
|
<ng-container
|
||||||
*ngIf="isSponsoredSubscription"
|
*ngIf="
|
||||||
>
|
subscription && canAdjustSeats && !subscription.cancelled && !subscriptionMarkedForCancel
|
||||||
{{ "removeSponsorship" | i18n }}
|
"
|
||||||
</button>
|
|
||||||
<h2 class="spaced-header">{{ "storage" | i18n }}</h2>
|
|
||||||
<p>{{ "subscriptionStorage" | i18n : sub.maxStorageGb || 0 : sub.storageName || "0 MB" }}</p>
|
|
||||||
<div class="progress">
|
|
||||||
<div
|
|
||||||
class="progress-bar bg-success"
|
|
||||||
role="progressbar"
|
|
||||||
[ngStyle]="{ width: storageProgressWidth + '%' }"
|
|
||||||
[attr.aria-valuenow]="storagePercentage"
|
|
||||||
aria-valuemin="0"
|
|
||||||
aria-valuemax="100"
|
|
||||||
>
|
>
|
||||||
{{ storagePercentage / 100 | percent }}
|
<div class="mt-3">
|
||||||
</div>
|
<app-adjust-subscription
|
||||||
</div>
|
[seatPrice]="seatPrice"
|
||||||
<ng-container *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel">
|
[organizationId]="organizationId"
|
||||||
<div class="mt-3">
|
[interval]="billingInterval"
|
||||||
<div class="d-flex" *ngIf="!showAdjustStorage">
|
[currentSeatCount]="seats"
|
||||||
<button bitButton buttonType="secondary" type="button" (click)="adjustStorage(true)">
|
[maxAutoscaleSeats]="maxAutoscaleSeats"
|
||||||
{{ "addStorage" | i18n }}
|
(onAdjusted)="subscriptionAdjusted()"
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
bitButton
|
|
||||||
buttonType="secondary"
|
|
||||||
type="button"
|
|
||||||
class="ml-1"
|
|
||||||
(click)="adjustStorage(false)"
|
|
||||||
>
|
>
|
||||||
{{ "removeStorage" | i18n }}
|
</app-adjust-subscription>
|
||||||
</button>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<button
|
||||||
|
bitButton
|
||||||
|
buttonType="danger"
|
||||||
|
type="button"
|
||||||
|
[bitAction]="removeSponsorship"
|
||||||
|
*ngIf="isSponsoredSubscription"
|
||||||
|
>
|
||||||
|
{{ "removeSponsorship" | i18n }}
|
||||||
|
</button>
|
||||||
|
<h2 class="spaced-header">{{ "storage" | i18n }}</h2>
|
||||||
|
<p>{{ "subscriptionStorage" | i18n : sub.maxStorageGb || 0 : sub.storageName || "0 MB" }}</p>
|
||||||
|
<div class="progress">
|
||||||
|
<div
|
||||||
|
class="progress-bar bg-success"
|
||||||
|
role="progressbar"
|
||||||
|
[ngStyle]="{ width: storageProgressWidth + '%' }"
|
||||||
|
[attr.aria-valuenow]="storagePercentage"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100"
|
||||||
|
>
|
||||||
|
{{ storagePercentage / 100 | percent }}
|
||||||
</div>
|
</div>
|
||||||
<app-adjust-storage
|
|
||||||
[storageGbPrice]="storageGbPrice"
|
|
||||||
[add]="adjustStorageAdd"
|
|
||||||
[organizationId]="organizationId"
|
|
||||||
[interval]="billingInterval"
|
|
||||||
(onAdjusted)="closeStorage(true)"
|
|
||||||
(onCanceled)="closeStorage(false)"
|
|
||||||
*ngIf="showAdjustStorage"
|
|
||||||
></app-adjust-storage>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ng-container *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel">
|
||||||
|
<div class="mt-3">
|
||||||
|
<div class="d-flex" *ngIf="!showAdjustStorage">
|
||||||
|
<button bitButton buttonType="secondary" type="button" (click)="adjustStorage(true)">
|
||||||
|
{{ "addStorage" | i18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
bitButton
|
||||||
|
buttonType="secondary"
|
||||||
|
type="button"
|
||||||
|
class="ml-1"
|
||||||
|
(click)="adjustStorage(false)"
|
||||||
|
>
|
||||||
|
{{ "removeStorage" | i18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<app-adjust-storage
|
||||||
|
[storageGbPrice]="storageGbPrice"
|
||||||
|
[add]="adjustStorageAdd"
|
||||||
|
[organizationId]="organizationId"
|
||||||
|
[interval]="billingInterval"
|
||||||
|
(onAdjusted)="closeStorage(true)"
|
||||||
|
(onCanceled)="closeStorage(false)"
|
||||||
|
*ngIf="showAdjustStorage"
|
||||||
|
></app-adjust-storage>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<h2 class="spaced-header">{{ "selfHostingTitle" | i18n }}</h2>
|
<h2 class="spaced-header">{{ "selfHostingTitle" | i18n }}</h2>
|
||||||
@ -214,20 +212,22 @@
|
|||||||
(onCanceled)="closeDownloadLicense()"
|
(onCanceled)="closeDownloadLicense()"
|
||||||
></app-download-license>
|
></app-download-license>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="spaced-header">{{ "additionalOptions" | i18n }}</h2>
|
<ng-container *ngIf="userOrg.canEditSubscription">
|
||||||
<p class="mb-4">
|
<h2 class="spaced-header">{{ "additionalOptions" | i18n }}</h2>
|
||||||
{{ "additionalOptionsDesc" | i18n }}
|
<p class="mb-4">
|
||||||
</p>
|
{{ "additionalOptionsDesc" | i18n }}
|
||||||
<div class="d-flex">
|
</p>
|
||||||
<button
|
<div class="d-flex">
|
||||||
bitButton
|
<button
|
||||||
buttonType="danger"
|
bitButton
|
||||||
[bitAction]="cancel"
|
buttonType="danger"
|
||||||
type="button"
|
[bitAction]="cancel"
|
||||||
class="ml-1"
|
type="button"
|
||||||
*ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
|
class="ml-1"
|
||||||
>
|
*ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
|
||||||
{{ "cancelSubscription" | i18n }}
|
>
|
||||||
</button>
|
{{ "cancelSubscription" | i18n }}
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -77,7 +77,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
|||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.userOrg = this.organizationService.get(this.organizationId);
|
this.userOrg = this.organizationService.get(this.organizationId);
|
||||||
if (this.userOrg.canManageBilling) {
|
if (this.userOrg.canViewSubscription) {
|
||||||
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<app-org-subscription-hidden
|
<app-org-subscription-hidden
|
||||||
*ngIf="firstLoaded && !userOrg.canManageBilling"
|
*ngIf="firstLoaded && !userOrg.canViewSubscription"
|
||||||
[providerName]="userOrg.providerName"
|
[providerName]="userOrg.providerName"
|
||||||
></app-org-subscription-hidden>
|
></app-org-subscription-hidden>
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDest
|
|||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.userOrg = this.organizationService.get(this.organizationId);
|
this.userOrg = this.organizationService.get(this.organizationId);
|
||||||
if (this.userOrg.canManageBilling) {
|
if (this.userOrg.canViewSubscription) {
|
||||||
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ export class VaultHeaderComponent {
|
|||||||
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = {
|
||||||
title: this.i18nService.t("upgradeOrganization"),
|
title: this.i18nService.t("upgradeOrganization"),
|
||||||
content: this.i18nService.t(
|
content: this.i18nService.t(
|
||||||
this.organization.canManageBilling
|
this.organization.canEditSubscription
|
||||||
? "freeOrgMaxCollectionReachedManageBilling"
|
? "freeOrgMaxCollectionReachedManageBilling"
|
||||||
: "freeOrgMaxCollectionReachedNoManageBilling",
|
: "freeOrgMaxCollectionReachedNoManageBilling",
|
||||||
this.organization.maxCollections
|
this.organization.maxCollections
|
||||||
@ -119,7 +119,7 @@ export class VaultHeaderComponent {
|
|||||||
type: SimpleDialogType.PRIMARY,
|
type: SimpleDialogType.PRIMARY,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.organization.canManageBilling) {
|
if (this.organization.canEditSubscription) {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade");
|
||||||
} else {
|
} else {
|
||||||
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok");
|
||||||
@ -133,7 +133,7 @@ export class VaultHeaderComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canManageBilling) {
|
if (result == SimpleDialogCloseType.ACCEPT && this.organization.canEditSubscription) {
|
||||||
this.router.navigate(["/organizations", this.organization.id, "billing", "subscription"], {
|
this.router.navigate(["/organizations", this.organization.id, "billing", "subscription"], {
|
||||||
queryParams: { upgrade: true },
|
queryParams: { upgrade: true },
|
||||||
});
|
});
|
||||||
|
@ -6,13 +6,17 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||||
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
||||||
import { OrganizationUserAcceptRequest } from "@bitwarden/common/abstractions/organization-user/requests";
|
import {
|
||||||
|
OrganizationUserAcceptInitRequest,
|
||||||
|
OrganizationUserAcceptRequest,
|
||||||
|
} from "@bitwarden/common/abstractions/organization-user/requests";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
|
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
|
|
||||||
import { BaseAcceptComponent } from "../app/common/base.accept.component";
|
import { BaseAcceptComponent } from "../app/common/base.accept.component";
|
||||||
@ -44,32 +48,33 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async authedHandler(qParams: Params): Promise<void> {
|
async authedHandler(qParams: Params): Promise<void> {
|
||||||
const needsReAuth = (await this.stateService.getOrganizationInvitation()) != null;
|
const initOrganization =
|
||||||
if (!needsReAuth) {
|
qParams.initOrganization != null && qParams.initOrganization.toLocaleLowerCase() === "true";
|
||||||
// Accepting an org invite requires authentication from a logged out state
|
if (initOrganization) {
|
||||||
this.messagingService.send("logout", { redirect: false });
|
this.actionPromise = this.acceptInitOrganizationFlow(qParams);
|
||||||
await this.prepareOrganizationInvitation(qParams);
|
} else {
|
||||||
return;
|
const needsReAuth = (await this.stateService.getOrganizationInvitation()) == null;
|
||||||
|
if (needsReAuth) {
|
||||||
|
// Accepting an org invite requires authentication from a logged out state
|
||||||
|
this.messagingService.send("logout", { redirect: false });
|
||||||
|
await this.prepareOrganizationInvitation(qParams);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User has already logged in and passed the Master Password policy check
|
||||||
|
this.actionPromise = this.acceptFlow(qParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User has already logged in and passed the Master Password policy check
|
|
||||||
this.actionPromise = this.prepareAcceptRequest(qParams).then(async (request) => {
|
|
||||||
await this.organizationUserService.postOrganizationUserAccept(
|
|
||||||
qParams.organizationId,
|
|
||||||
qParams.organizationUserId,
|
|
||||||
request
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.stateService.setOrganizationInvitation(null);
|
|
||||||
await this.actionPromise;
|
await this.actionPromise;
|
||||||
|
await this.stateService.setOrganizationInvitation(null);
|
||||||
this.platformUtilService.showToast(
|
this.platformUtilService.showToast(
|
||||||
"success",
|
"success",
|
||||||
this.i18nService.t("inviteAccepted"),
|
this.i18nService.t("inviteAccepted"),
|
||||||
this.i18nService.t("inviteAcceptedDesc"),
|
initOrganization
|
||||||
|
? this.i18nService.t("inviteInitAcceptedDesc")
|
||||||
|
: this.i18nService.t("inviteAcceptedDesc"),
|
||||||
{ timeout: 10000 }
|
{ timeout: 10000 }
|
||||||
);
|
);
|
||||||
|
|
||||||
this.router.navigate(["/vault"]);
|
this.router.navigate(["/vault"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +82,51 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
|
|||||||
await this.prepareOrganizationInvitation(qParams);
|
await this.prepareOrganizationInvitation(qParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async acceptInitOrganizationFlow(qParams: Params): Promise<any> {
|
||||||
|
return this.prepareAcceptInitRequest(qParams).then((request) =>
|
||||||
|
this.organizationUserService.postOrganizationUserAcceptInit(
|
||||||
|
qParams.organizationId,
|
||||||
|
qParams.organizationUserId,
|
||||||
|
request
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async acceptFlow(qParams: Params): Promise<any> {
|
||||||
|
return this.prepareAcceptRequest(qParams).then((request) =>
|
||||||
|
this.organizationUserService.postOrganizationUserAccept(
|
||||||
|
qParams.organizationId,
|
||||||
|
qParams.organizationUserId,
|
||||||
|
request
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async prepareAcceptInitRequest(
|
||||||
|
qParams: Params
|
||||||
|
): Promise<OrganizationUserAcceptInitRequest> {
|
||||||
|
const request = new OrganizationUserAcceptInitRequest();
|
||||||
|
request.token = qParams.token;
|
||||||
|
|
||||||
|
const [encryptedOrgShareKey, orgShareKey] = await this.cryptoService.makeShareKey();
|
||||||
|
const [orgPublicKey, encryptedOrgPrivateKey] = await this.cryptoService.makeKeyPair(
|
||||||
|
orgShareKey
|
||||||
|
);
|
||||||
|
const collection = await this.cryptoService.encrypt(
|
||||||
|
this.i18nService.t("defaultCollection"),
|
||||||
|
orgShareKey
|
||||||
|
);
|
||||||
|
|
||||||
|
request.key = encryptedOrgShareKey.encryptedString;
|
||||||
|
request.keys = new OrganizationKeysRequest(
|
||||||
|
orgPublicKey,
|
||||||
|
encryptedOrgPrivateKey.encryptedString
|
||||||
|
);
|
||||||
|
request.collectionName = collection.encryptedString;
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
private async prepareAcceptRequest(qParams: Params): Promise<OrganizationUserAcceptRequest> {
|
private async prepareAcceptRequest(qParams: Params): Promise<OrganizationUserAcceptRequest> {
|
||||||
const request = new OrganizationUserAcceptRequest();
|
const request = new OrganizationUserAcceptRequest();
|
||||||
request.token = qParams.token;
|
request.token = qParams.token;
|
||||||
|
@ -3126,6 +3126,9 @@
|
|||||||
"inviteAcceptedDesc": {
|
"inviteAcceptedDesc": {
|
||||||
"message": "You can access this organization once an administrator confirms your membership. We'll send you an email when that happens."
|
"message": "You can access this organization once an administrator confirms your membership. We'll send you an email when that happens."
|
||||||
},
|
},
|
||||||
|
"inviteInitAcceptedDesc": {
|
||||||
|
"message": "You can now access this organization."
|
||||||
|
},
|
||||||
"inviteAcceptFailed": {
|
"inviteAcceptFailed": {
|
||||||
"message": "Unable to accept invitation. Ask an organization admin to send a new invitation."
|
"message": "Unable to accept invitation. Ask an organization admin to send a new invitation."
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ListResponse } from "../../models/response/list.response";
|
import { ListResponse } from "../../models/response/list.response";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
OrganizationUserAcceptInitRequest,
|
||||||
OrganizationUserAcceptRequest,
|
OrganizationUserAcceptRequest,
|
||||||
OrganizationUserBulkConfirmRequest,
|
OrganizationUserBulkConfirmRequest,
|
||||||
OrganizationUserConfirmRequest,
|
OrganizationUserConfirmRequest,
|
||||||
@ -94,6 +95,20 @@ export abstract class OrganizationUserService {
|
|||||||
ids: string[]
|
ids: string[]
|
||||||
): Promise<ListResponse<OrganizationUserBulkResponse>>;
|
): Promise<ListResponse<OrganizationUserBulkResponse>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept an invitation to initialize and join an organization created via the Admin Portal **only**.
|
||||||
|
* This is only used once for the initial Owner, because it also creates the organization's encryption keys.
|
||||||
|
* This should not be used for organizations created via the Web client.
|
||||||
|
* @param organizationId - Identifier for the organization to accept
|
||||||
|
* @param id - Organization user identifier
|
||||||
|
* @param request - Request details for accepting the invitation
|
||||||
|
*/
|
||||||
|
abstract postOrganizationUserAcceptInit(
|
||||||
|
organizationId: string,
|
||||||
|
id: string,
|
||||||
|
request: OrganizationUserAcceptInitRequest
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept an organization user invitation
|
* Accept an organization user invitation
|
||||||
* @param organizationId - Identifier for the organization to accept
|
* @param organizationId - Identifier for the organization to accept
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
export * from "./organization-user-accept-init.request";
|
||||||
export * from "./organization-user-accept.request";
|
export * from "./organization-user-accept.request";
|
||||||
export * from "./organization-user-bulk-confirm.request";
|
export * from "./organization-user-bulk-confirm.request";
|
||||||
export * from "./organization-user-confirm.request";
|
export * from "./organization-user-confirm.request";
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { OrganizationKeysRequest } from "../../../admin-console/models/request/organization-keys.request";
|
||||||
|
|
||||||
|
export class OrganizationUserAcceptInitRequest {
|
||||||
|
token: string;
|
||||||
|
key: string;
|
||||||
|
keys: OrganizationKeysRequest;
|
||||||
|
collectionName: string;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { ProductType } from "../../../enums";
|
import { ProductType, ProviderType } from "../../../enums";
|
||||||
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
||||||
import { PermissionsApi } from "../api/permissions.api";
|
import { PermissionsApi } from "../api/permissions.api";
|
||||||
import { ProfileOrganizationResponse } from "../response/profile-organization.response";
|
import { ProfileOrganizationResponse } from "../response/profile-organization.response";
|
||||||
@ -36,6 +36,7 @@ export class OrganizationData {
|
|||||||
hasPublicAndPrivateKeys: boolean;
|
hasPublicAndPrivateKeys: boolean;
|
||||||
providerId: string;
|
providerId: string;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
|
providerType?: ProviderType;
|
||||||
isProviderUser: boolean;
|
isProviderUser: boolean;
|
||||||
familySponsorshipFriendlyName: string;
|
familySponsorshipFriendlyName: string;
|
||||||
familySponsorshipAvailable: boolean;
|
familySponsorshipAvailable: boolean;
|
||||||
@ -80,6 +81,7 @@ export class OrganizationData {
|
|||||||
this.hasPublicAndPrivateKeys = response.hasPublicAndPrivateKeys;
|
this.hasPublicAndPrivateKeys = response.hasPublicAndPrivateKeys;
|
||||||
this.providerId = response.providerId;
|
this.providerId = response.providerId;
|
||||||
this.providerName = response.providerName;
|
this.providerName = response.providerName;
|
||||||
|
this.providerType = response.providerType;
|
||||||
this.familySponsorshipFriendlyName = response.familySponsorshipFriendlyName;
|
this.familySponsorshipFriendlyName = response.familySponsorshipFriendlyName;
|
||||||
this.familySponsorshipAvailable = response.familySponsorshipAvailable;
|
this.familySponsorshipAvailable = response.familySponsorshipAvailable;
|
||||||
this.planProductType = response.planProductType;
|
this.planProductType = response.planProductType;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ProductType } from "../../../enums";
|
import { ProductType, ProviderType } from "../../../enums";
|
||||||
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
||||||
import { PermissionsApi } from "../api/permissions.api";
|
import { PermissionsApi } from "../api/permissions.api";
|
||||||
import { OrganizationData } from "../data/organization.data";
|
import { OrganizationData } from "../data/organization.data";
|
||||||
@ -38,6 +38,7 @@ export class Organization {
|
|||||||
hasPublicAndPrivateKeys: boolean;
|
hasPublicAndPrivateKeys: boolean;
|
||||||
providerId: string;
|
providerId: string;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
|
providerType?: ProviderType;
|
||||||
isProviderUser: boolean;
|
isProviderUser: boolean;
|
||||||
familySponsorshipFriendlyName: string;
|
familySponsorshipFriendlyName: string;
|
||||||
familySponsorshipAvailable: boolean;
|
familySponsorshipAvailable: boolean;
|
||||||
@ -86,6 +87,7 @@ export class Organization {
|
|||||||
this.hasPublicAndPrivateKeys = obj.hasPublicAndPrivateKeys;
|
this.hasPublicAndPrivateKeys = obj.hasPublicAndPrivateKeys;
|
||||||
this.providerId = obj.providerId;
|
this.providerId = obj.providerId;
|
||||||
this.providerName = obj.providerName;
|
this.providerName = obj.providerName;
|
||||||
|
this.providerType = obj.providerType;
|
||||||
this.isProviderUser = obj.isProviderUser;
|
this.isProviderUser = obj.isProviderUser;
|
||||||
this.familySponsorshipFriendlyName = obj.familySponsorshipFriendlyName;
|
this.familySponsorshipFriendlyName = obj.familySponsorshipFriendlyName;
|
||||||
this.familySponsorshipAvailable = obj.familySponsorshipAvailable;
|
this.familySponsorshipAvailable = obj.familySponsorshipAvailable;
|
||||||
@ -197,8 +199,26 @@ export class Organization {
|
|||||||
return this.canManagePolicies;
|
return this.canManagePolicies;
|
||||||
}
|
}
|
||||||
|
|
||||||
get canManageBilling() {
|
get canViewSubscription() {
|
||||||
return this.isOwner && (this.isProviderUser || !this.hasProvider);
|
if (this.canEditSubscription) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.hasProvider && this.providerType === ProviderType.Msp
|
||||||
|
? this.isProviderUser
|
||||||
|
: this.isOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canEditSubscription() {
|
||||||
|
return this.hasProvider ? this.isProviderUser : this.isOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canEditPaymentMethods() {
|
||||||
|
return this.canEditSubscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canViewBillingHistory() {
|
||||||
|
return this.canEditSubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasProvider() {
|
get hasProvider() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ProductType } from "../../../enums";
|
import { ProductType, ProviderType } from "../../../enums";
|
||||||
import { BaseResponse } from "../../../models/response/base.response";
|
import { BaseResponse } from "../../../models/response/base.response";
|
||||||
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
import { OrganizationUserStatusType, OrganizationUserType } from "../../enums";
|
||||||
import { PermissionsApi } from "../api/permissions.api";
|
import { PermissionsApi } from "../api/permissions.api";
|
||||||
@ -37,6 +37,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
|||||||
userId: string;
|
userId: string;
|
||||||
providerId: string;
|
providerId: string;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
|
providerType?: ProviderType;
|
||||||
familySponsorshipFriendlyName: string;
|
familySponsorshipFriendlyName: string;
|
||||||
familySponsorshipAvailable: boolean;
|
familySponsorshipAvailable: boolean;
|
||||||
planProductType: ProductType;
|
planProductType: ProductType;
|
||||||
@ -82,6 +83,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
|||||||
this.userId = this.getResponseProperty("UserId");
|
this.userId = this.getResponseProperty("UserId");
|
||||||
this.providerId = this.getResponseProperty("ProviderId");
|
this.providerId = this.getResponseProperty("ProviderId");
|
||||||
this.providerName = this.getResponseProperty("ProviderName");
|
this.providerName = this.getResponseProperty("ProviderName");
|
||||||
|
this.providerType = this.getResponseProperty("ProviderType");
|
||||||
this.familySponsorshipFriendlyName = this.getResponseProperty("FamilySponsorshipFriendlyName");
|
this.familySponsorshipFriendlyName = this.getResponseProperty("FamilySponsorshipFriendlyName");
|
||||||
this.familySponsorshipAvailable = this.getResponseProperty("FamilySponsorshipAvailable");
|
this.familySponsorshipAvailable = this.getResponseProperty("FamilySponsorshipAvailable");
|
||||||
this.planProductType = this.getResponseProperty("PlanProductType");
|
this.planProductType = this.getResponseProperty("PlanProductType");
|
||||||
|
@ -75,7 +75,7 @@ export class BillingSubscriptionItemResponse extends BaseResponse {
|
|||||||
|
|
||||||
export class BillingSubscriptionUpcomingInvoiceResponse extends BaseResponse {
|
export class BillingSubscriptionUpcomingInvoiceResponse extends BaseResponse {
|
||||||
date: string;
|
date: string;
|
||||||
amount: number;
|
amount?: number;
|
||||||
|
|
||||||
constructor(response: any) {
|
constructor(response: any) {
|
||||||
super(response);
|
super(response);
|
||||||
|
@ -16,6 +16,7 @@ export * from "./log-level-type.enum";
|
|||||||
export * from "./native-messaging-version.enum";
|
export * from "./native-messaging-version.enum";
|
||||||
export * from "./notification-type.enum";
|
export * from "./notification-type.enum";
|
||||||
export * from "./product-type.enum";
|
export * from "./product-type.enum";
|
||||||
|
export * from "./provider-type.enum";
|
||||||
export * from "./secure-note-type.enum";
|
export * from "./secure-note-type.enum";
|
||||||
export * from "./state-version.enum";
|
export * from "./state-version.enum";
|
||||||
export * from "./storage-location.enum";
|
export * from "./storage-location.enum";
|
||||||
|
4
libs/common/src/enums/provider-type.enum.ts
Normal file
4
libs/common/src/enums/provider-type.enum.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum ProviderType {
|
||||||
|
Msp = 0,
|
||||||
|
Reseller = 1,
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { ApiService } from "../../abstractions/api.service";
|
import { ApiService } from "../../abstractions/api.service";
|
||||||
import { OrganizationUserService } from "../../abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "../../abstractions/organization-user/organization-user.service";
|
||||||
import {
|
import {
|
||||||
|
OrganizationUserAcceptInitRequest,
|
||||||
OrganizationUserAcceptRequest,
|
OrganizationUserAcceptRequest,
|
||||||
OrganizationUserBulkConfirmRequest,
|
OrganizationUserBulkConfirmRequest,
|
||||||
OrganizationUserConfirmRequest,
|
OrganizationUserConfirmRequest,
|
||||||
@ -135,6 +136,20 @@ export class OrganizationUserServiceImplementation implements OrganizationUserSe
|
|||||||
return new ListResponse(r, OrganizationUserBulkResponse);
|
return new ListResponse(r, OrganizationUserBulkResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postOrganizationUserAcceptInit(
|
||||||
|
organizationId: string,
|
||||||
|
id: string,
|
||||||
|
request: OrganizationUserAcceptInitRequest
|
||||||
|
): Promise<void> {
|
||||||
|
return this.apiService.send(
|
||||||
|
"POST",
|
||||||
|
"/organizations/" + organizationId + "/users/" + id + "/accept-init",
|
||||||
|
request,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
postOrganizationUserAccept(
|
postOrganizationUserAccept(
|
||||||
organizationId: string,
|
organizationId: string,
|
||||||
id: string,
|
id: string,
|
||||||
|
Loading…
Reference in New Issue
Block a user