mirror of
https://github.com/bitwarden/browser
synced 2024-12-28 02:43:04 +01:00
Feature/families for enterprise (#549)
* Families for enterprise/account settings (#541) * Add node tests to pipeline (#525) * Add support for crypto agent (#520) * feat: add an importer for Safari (CSV) (#512) * feat(importers/safariCsvImporter): add the importer for Safari (CSV) * Revert changes to package-lock.json Co-authored-by: Thomas Rittson <trittson@bitwarden.com> * Dynamically set electron user agent (#524) * Dynamically set electron user agent * PR review * linter fixes * Test agent static version does not change * Fix formatting * Add role="alert" to callouts only when enforceAlert is passed (#528) * Add role="alert" to callouts when enforceAlert is passed * Remove ElementRef and do a different way * Rename input variable * Add PR template (#529) * Allow managers to create collections (#530) * Pass in null for sso organziation for now. (#531) This will bypass cryptoagent * Add Linked Field as custom field type (#431) * Basic proof of concept of Linked custom fields * Linked Fields for all cipher types, use dropdown * Move linkedFieldOptions to view models * Move add-edit custom fields to own component * Fix change handling if cipherType changes * Use Field.LinkedId to store linked field info * Refactor accessors in cipherView for type safety * Use map for linkedFieldOptions * Refactor: use decorators to record linkable info * Add ItemView * Use enums for linked field ids * Add union type for linkedId enums, add jsdoc comment * Use parameter properties for linkedFieldOption Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Fix type casting Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Update electron to 14.2.0 (#534) * Update electron to 14.1.1 * Update electron to 14.2.0 and fix it to this version * Removed ^ from electron in electron/package-lock.json * [Linked fields] Reset linkedIds if cipher type changes (#535) * Reset linkedIds if cipher type changes * Only reset linkedId if !editmode * Add call to server * Fix linting * Add call to server * Fix linting * Run linting * Add new properties to organization * Remove organizationUserId from request model * Added in org sponsorship calls * Sponsorship redeem existing org flow Co-authored-by: Matt Gibson <mgibson@bitwarden.com> Co-authored-by: Oscar Hinton <oscar@oscarhinton.com> Co-authored-by: pan93412 <pan93412@gmail.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Robyn MacCallum <nickersthecat@gmail.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com> * Revoke sponsorship uses organization id * Expect information in billing items on whether the item is sponsored * Families for enterprise/redeem card (#546) * Add userservice helper * Run linter * Add resend email to api service (#548) * Remove unneeded imports * Remove unneeded files * Add newline * Reorder import * Remove accidental newline * Fix lint issue Co-authored-by: Matt Gibson <mgibson@bitwarden.com> Co-authored-by: Oscar Hinton <oscar@oscarhinton.com> Co-authored-by: pan93412 <pan93412@gmail.com> Co-authored-by: Thomas Rittson <trittson@bitwarden.com> Co-authored-by: Robyn MacCallum <nickersthecat@gmail.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
parent
f4c66b2c8c
commit
b4f475251a
@ -32,6 +32,8 @@ import { ImportOrganizationCiphersRequest } from '../models/request/importOrgani
|
||||
import { KdfRequest } from '../models/request/kdfRequest';
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
import { KeysRequest } from '../models/request/keysRequest';
|
||||
import { OrganizationSponsorshipCreateRequest } from '../models/request/organization/organizationSponsorshipCreateRequest';
|
||||
import { OrganizationSponsorshipRedeemRequest } from '../models/request/organization/organizationSponsorshipRedeemRequest';
|
||||
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
|
||||
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
|
||||
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
|
||||
@ -453,6 +455,12 @@ export abstract class ApiService {
|
||||
|
||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
||||
|
||||
postCreateSponsorship: (sponsorshipOrgId: string, request: OrganizationSponsorshipCreateRequest) => Promise<void>;
|
||||
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
||||
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
||||
postRedeemSponsorship: (sponsorshipToken: string, request: OrganizationSponsorshipRedeemRequest) => Promise<void>;
|
||||
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
||||
|
||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
||||
postUserKeyToKeyConnector: (keyConnectorUrl: string, request: KeyConnectorUserKeyRequest) => Promise<void>;
|
||||
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
||||
|
@ -21,6 +21,7 @@ export abstract class UserService {
|
||||
clear: () => Promise<any>;
|
||||
isAuthenticated: () => Promise<boolean>;
|
||||
canAccessPremium: () => Promise<boolean>;
|
||||
canManageSponsorships: () => Promise<boolean>;
|
||||
getOrganization: (id: string) => Promise<Organization>;
|
||||
getOrganizationByIdentifier: (identifier: string) => Promise<Organization>;
|
||||
getAllOrganizations: () => Promise<Organization[]>;
|
||||
|
3
common/src/enums/planSponsorshipType.ts
Normal file
3
common/src/enums/planSponsorshipType.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export enum PlanSponsorshipType {
|
||||
FamiliesForEnterprise = 0,
|
||||
}
|
@ -2,6 +2,8 @@ import { ProfileOrganizationResponse } from '../response/profileOrganizationResp
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
export class OrganizationData {
|
||||
@ -34,6 +36,9 @@ export class OrganizationData {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
@ -66,6 +71,9 @@ export class OrganizationData {
|
||||
this.hasPublicAndPrivateKeys = response.hasPublicAndPrivateKeys;
|
||||
this.providerId = response.providerId;
|
||||
this.providerName = response.providerName;
|
||||
this.familySponsorshipFriendlyName = response.familySponsorshipFriendlyName;
|
||||
this.familySponsorshipAvailable = response.familySponsorshipAvailable;
|
||||
this.planProductType = response.planProductType;
|
||||
this.keyConnectorEnabled = response.keyConnectorEnabled;
|
||||
this.keyConnectorUrl = response.keyConnectorUrl;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { OrganizationData } from '../data/organizationData';
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
|
||||
@ -35,6 +36,9 @@ export class Organization {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
@ -72,6 +76,9 @@ export class Organization {
|
||||
this.providerId = obj.providerId;
|
||||
this.providerName = obj.providerName;
|
||||
this.isProviderUser = obj.isProviderUser;
|
||||
this.familySponsorshipFriendlyName = obj.familySponsorshipFriendlyName;
|
||||
this.familySponsorshipAvailable = obj.familySponsorshipAvailable;
|
||||
this.planProductType = obj.planProductType;
|
||||
this.keyConnectorEnabled = obj.keyConnectorEnabled;
|
||||
this.keyConnectorUrl = obj.keyConnectorUrl;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
import { PlanSponsorshipType } from '../../../enums/planSponsorshipType';
|
||||
|
||||
export class OrganizationSponsorshipCreateRequest {
|
||||
sponsoredEmail: string;
|
||||
planSponsorshipType: PlanSponsorshipType;
|
||||
friendlyName: string;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { PlanSponsorshipType } from '../../../enums/planSponsorshipType';
|
||||
|
||||
export class OrganizationSponsorshipRedeemRequest {
|
||||
planSponsorshipType: PlanSponsorshipType;
|
||||
sponsoredOrganizationId: string;
|
||||
}
|
@ -2,6 +2,7 @@ import { BaseResponse } from './baseResponse';
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { ProductType } from '../../enums/productType';
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
export class ProfileOrganizationResponse extends BaseResponse {
|
||||
@ -34,6 +35,9 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
userId: string;
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
familySponsorshipFriendlyName: string;
|
||||
familySponsorshipAvailable: boolean;
|
||||
planProductType: ProductType;
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
@ -68,6 +72,9 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
this.userId = this.getResponseProperty('UserId');
|
||||
this.providerId = this.getResponseProperty('ProviderId');
|
||||
this.providerName = this.getResponseProperty('ProviderName');
|
||||
this.familySponsorshipFriendlyName = this.getResponseProperty('FamilySponsorshipFriendlyName');
|
||||
this.familySponsorshipAvailable = this.getResponseProperty('FamilySponsorshipAvailable');
|
||||
this.planProductType = this.getResponseProperty('PlanProductType');
|
||||
this.keyConnectorEnabled = this.getResponseProperty('KeyConnectorEnabled') ?? false;
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ export class BillingSubscriptionItemResponse extends BaseResponse {
|
||||
amount: number;
|
||||
quantity: number;
|
||||
interval: string;
|
||||
sponsoredSubscriptionItem: boolean;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@ -66,6 +67,7 @@ export class BillingSubscriptionItemResponse extends BaseResponse {
|
||||
this.amount = this.getResponseProperty('Amount');
|
||||
this.quantity = this.getResponseProperty('Quantity');
|
||||
this.interval = this.getResponseProperty('Interval');
|
||||
this.sponsoredSubscriptionItem = this.getResponseProperty('SponsoredSubscriptionItem');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest
|
||||
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
|
||||
import { KdfRequest } from '../models/request/kdfRequest';
|
||||
import { KeysRequest } from '../models/request/keysRequest';
|
||||
import { OrganizationSponsorshipCreateRequest } from '../models/request/organization/organizationSponsorshipCreateRequest';
|
||||
import { OrganizationSponsorshipRedeemRequest } from '../models/request/organization/organizationSponsorshipRedeemRequest';
|
||||
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
|
||||
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
|
||||
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
|
||||
@ -172,6 +174,8 @@ import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKe
|
||||
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
|
||||
import { SendAccessView } from '../models/view/sendAccessView';
|
||||
|
||||
|
||||
|
||||
export class ApiService implements ApiServiceAbstraction {
|
||||
protected apiKeyRefresh: (clientId: string, clientSecret: string) => Promise<any>;
|
||||
private device: DeviceType;
|
||||
@ -1558,6 +1562,35 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
}
|
||||
}
|
||||
|
||||
async postCreateSponsorship(sponsoredOrgId: string, request: OrganizationSponsorshipCreateRequest): Promise<void> {
|
||||
return await this.send('POST',
|
||||
'/organization/sponsorship/' + sponsoredOrgId + '/families-for-enterprise',
|
||||
request, true, false);
|
||||
}
|
||||
|
||||
async deleteRevokeSponsorship(sponsoringOrganizationId: string): Promise<void> {
|
||||
return await this.send('DELETE',
|
||||
'/organization/sponsorship/' + sponsoringOrganizationId,
|
||||
null, true, false);
|
||||
}
|
||||
|
||||
async deleteRemoveSponsorship(sponsoringOrgId: string): Promise<void> {
|
||||
return await this.send('DELETE',
|
||||
'/organization/sponsorship/sponsored/' + sponsoringOrgId,
|
||||
null, true, false);
|
||||
}
|
||||
async postRedeemSponsorship(sponsorshipToken: string, request: OrganizationSponsorshipRedeemRequest): Promise<void> {
|
||||
return await this.send('POST', '/organization/sponsorship/redeem?sponsorshipToken=' + encodeURIComponent(sponsorshipToken),
|
||||
request, true, false);
|
||||
}
|
||||
|
||||
async postResendSponsorshipOffer(sponsoringOrgId: string): Promise<void> {
|
||||
return await this.send('POST',
|
||||
'/organization/sponsorship/' + sponsoringOrgId + '/families-for-enterprise/resend',
|
||||
null, true, false);
|
||||
}
|
||||
|
||||
|
||||
protected async doAuthRefresh(): Promise<void> {
|
||||
const refreshToken = await this.tokenService.getRefreshToken();
|
||||
if (refreshToken != null && refreshToken !== '') {
|
||||
|
@ -156,6 +156,11 @@ export class UserService implements UserServiceAbstraction {
|
||||
return false;
|
||||
}
|
||||
|
||||
async canManageSponsorships(): Promise<boolean> {
|
||||
const orgs = await this.getAllOrganizations();
|
||||
return orgs.some(o => o.familySponsorshipAvailable || o.familySponsorshipFriendlyName !== null);
|
||||
}
|
||||
|
||||
async getOrganization(id: string): Promise<Organization> {
|
||||
const userId = await this.getUserId();
|
||||
const organizations = await this.storageService.get<{ [id: string]: OrganizationData; }>(
|
||||
|
Loading…
Reference in New Issue
Block a user