diff --git a/src/models/data/collectionData.ts b/src/models/data/collectionData.ts index ff226d315ed..5d49ae2389c 100644 --- a/src/models/data/collectionData.ts +++ b/src/models/data/collectionData.ts @@ -1,4 +1,4 @@ -import { CollectionResponse } from '../response/collectionResponse'; +import { CollectionDetailsResponse } from '../response/collectionResponse'; export class CollectionData { id: string; @@ -6,7 +6,7 @@ export class CollectionData { name: string; readOnly: boolean; - constructor(response: CollectionResponse) { + constructor(response: CollectionDetailsResponse) { this.id = response.id; this.organizationId = response.organizationId; this.name = response.name; diff --git a/src/models/request/collectionRequest.ts b/src/models/request/collectionRequest.ts index 38e62a449f3..e5f427624b8 100644 --- a/src/models/request/collectionRequest.ts +++ b/src/models/request/collectionRequest.ts @@ -1,7 +1,10 @@ import { Collection } from '../domain/collection'; +import { SelectionReadOnlyRequest } from './selectionReadOnlyRequest'; + export class CollectionRequest { name: string; + groups: SelectionReadOnlyRequest[] = []; constructor(collection: Collection) { this.name = collection.name ? collection.name.encryptedString : null; diff --git a/src/models/request/groupRequest.ts b/src/models/request/groupRequest.ts new file mode 100644 index 00000000000..d3e18cf1d75 --- /dev/null +++ b/src/models/request/groupRequest.ts @@ -0,0 +1,8 @@ +import { SelectionReadOnlyRequest } from './selectionReadOnlyRequest'; + +export class GroupRequest { + name: string; + accessAll: boolean; + externalId: string; + collections: SelectionReadOnlyRequest[] = []; +} diff --git a/src/models/request/selectionReadOnlyRequest.ts b/src/models/request/selectionReadOnlyRequest.ts new file mode 100644 index 00000000000..e947b0a3644 --- /dev/null +++ b/src/models/request/selectionReadOnlyRequest.ts @@ -0,0 +1,9 @@ +export class SelectionReadOnlyRequest { + id: string; + readOnly: boolean; + + constructor(id: string, readOnly: boolean) { + this.id = id; + this.readOnly = readOnly; + } +} diff --git a/src/models/response/collectionResponse.ts b/src/models/response/collectionResponse.ts index 525bf60e34e..d04304b785a 100644 --- a/src/models/response/collectionResponse.ts +++ b/src/models/response/collectionResponse.ts @@ -1,13 +1,33 @@ +import { SelectionReadOnlyResponse } from './selectionReadOnlyResponse'; + export class CollectionResponse { id: string; organizationId: string; name: string; - readOnly: boolean; constructor(response: any) { this.id = response.Id; this.organizationId = response.OrganizationId; this.name = response.Name; + } +} + +export class CollectionDetailsResponse extends CollectionResponse { + readOnly: boolean; + + constructor(response: any) { + super(response); this.readOnly = response.ReadOnly || false; } } + +export class CollectionGroupDetailsResponse extends CollectionResponse { + groups: SelectionReadOnlyResponse[] = []; + + constructor(response: any) { + super(response); + if (response.Groups != null) { + this.groups = response.Collections.map((g: any) => new SelectionReadOnlyResponse(g)); + } + } +} diff --git a/src/models/response/collectionUserResponse.ts b/src/models/response/collectionUserResponse.ts new file mode 100644 index 00000000000..ea36e473e6b --- /dev/null +++ b/src/models/response/collectionUserResponse.ts @@ -0,0 +1,22 @@ +import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType'; +import { OrganizationUserType } from '../../enums/organizationUserType'; + +export class CollectionUserResponse { + organizationUserId: string; + accessAll: boolean; + name: string; + email: string; + type: OrganizationUserType; + status: OrganizationUserStatusType; + readOnly: boolean; + + constructor(response: any) { + this.organizationUserId = response.OrganizationUserId; + this.accessAll = response.AccessAll; + this.name = response.Name; + this.email = response.Email; + this.type = response.Type; + this.status = response.Status; + this.readOnly = response.ReadOnly; + } +} diff --git a/src/models/response/groupResponse.ts b/src/models/response/groupResponse.ts new file mode 100644 index 00000000000..960e077a2ad --- /dev/null +++ b/src/models/response/groupResponse.ts @@ -0,0 +1,28 @@ +import { SelectionReadOnlyResponse } from './selectionReadOnlyResponse'; + +export class GroupResponse { + id: string; + organizationId: string; + name: string; + accessAll: boolean; + externalId: string; + + constructor(response: any) { + this.id = response.Id; + this.organizationId = response.OrganizationId; + this.name = response.Name; + this.accessAll = response.AccessAll; + this.externalId = response.ExternalId; + } +} + +export class GroupDetailsResponse extends GroupResponse { + collections: SelectionReadOnlyResponse[] = []; + + constructor(response: any) { + super(response); + if (response.Collections != null) { + this.collections = response.Collections.map((c: any) => new SelectionReadOnlyResponse(c)); + } + } +} diff --git a/src/models/response/groupUserResponse.ts b/src/models/response/groupUserResponse.ts new file mode 100644 index 00000000000..0d8d25c30df --- /dev/null +++ b/src/models/response/groupUserResponse.ts @@ -0,0 +1,20 @@ +import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType'; +import { OrganizationUserType } from '../../enums/organizationUserType'; + +export class GroupUserResponse { + organizationUserId: string; + accessAll: boolean; + name: string; + email: string; + type: OrganizationUserType; + status: OrganizationUserStatusType; + + constructor(response: any) { + this.organizationUserId = response.OrganizationUserId; + this.accessAll = response.AccessAll; + this.name = response.Name; + this.email = response.Email; + this.type = response.Type; + this.status = response.Status; + } +} diff --git a/src/models/response/selectionReadOnlyResponse.ts b/src/models/response/selectionReadOnlyResponse.ts new file mode 100644 index 00000000000..c5f2c2dffde --- /dev/null +++ b/src/models/response/selectionReadOnlyResponse.ts @@ -0,0 +1,9 @@ +export class SelectionReadOnlyResponse { + id: string; + readOnly: boolean; + + constructor(response: any) { + this.id = response.Id; + this.readOnly = response.ReadOnly; + } +} diff --git a/src/models/response/syncResponse.ts b/src/models/response/syncResponse.ts index 58c02807399..3d0b7410990 100644 --- a/src/models/response/syncResponse.ts +++ b/src/models/response/syncResponse.ts @@ -1,5 +1,5 @@ import { CipherResponse } from './cipherResponse'; -import { CollectionResponse } from './collectionResponse'; +import { CollectionDetailsResponse } from './collectionResponse'; import { DomainsResponse } from './domainsResponse'; import { FolderResponse } from './folderResponse'; import { ProfileResponse } from './profileResponse'; @@ -7,7 +7,7 @@ import { ProfileResponse } from './profileResponse'; export class SyncResponse { profile?: ProfileResponse; folders: FolderResponse[] = []; - collections: CollectionResponse[] = []; + collections: CollectionDetailsResponse[] = []; ciphers: CipherResponse[] = []; domains?: DomainsResponse; @@ -24,7 +24,7 @@ export class SyncResponse { if (response.Collections) { response.Collections.forEach((collection: any) => { - this.collections.push(new CollectionResponse(collection)); + this.collections.push(new CollectionDetailsResponse(collection)); }); } diff --git a/src/services/api.service.ts b/src/services/api.service.ts index 7eb3331f450..e8a1cdedbd0 100644 --- a/src/services/api.service.ts +++ b/src/services/api.service.ts @@ -12,9 +12,11 @@ import { CipherBulkShareRequest } from '../models/request/cipherBulkShareRequest import { CipherCollectionsRequest } from '../models/request/cipherCollectionsRequest'; import { CipherRequest } from '../models/request/cipherRequest'; import { CipherShareRequest } from '../models/request/cipherShareRequest'; +import { CollectionRequest } from '../models/request/collectionRequest'; import { EmailRequest } from '../models/request/emailRequest'; import { EmailTokenRequest } from '../models/request/emailTokenRequest'; import { FolderRequest } from '../models/request/folderRequest'; +import { GroupRequest } from '../models/request/groupRequest'; import { ImportCiphersRequest } from '../models/request/importCiphersRequest'; import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest'; import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest'; @@ -40,10 +42,19 @@ import { UpdateTwoFactorYubioOtpRequest } from '../models/request/updateTwoFacto import { BillingResponse } from '../models/response/billingResponse'; import { CipherResponse } from '../models/response/cipherResponse'; -import { CollectionResponse } from '../models/response/collectionResponse'; +import { + CollectionGroupDetailsResponse, + CollectionResponse, +} from '../models/response/collectionResponse'; +import { CollectionUserResponse } from '../models/response/collectionUserResponse'; import { DomainsResponse } from '../models/response/domainsResponse'; import { ErrorResponse } from '../models/response/errorResponse'; import { FolderResponse } from '../models/response/folderResponse'; +import { + GroupDetailsResponse, + GroupResponse, +} from '../models/response/groupResponse'; +import { GroupUserResponse } from '../models/response/groupUserResponse'; import { IdentityTokenResponse } from '../models/response/identityTokenResponse'; import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse'; import { ListResponse } from '../models/response/listResponse'; @@ -350,11 +361,70 @@ export class ApiService implements ApiServiceAbstraction { // Collections APIs + async getCollectionDetails(organizationId: string, id: string): Promise { + const r = await this.send('GET', '/organizations/' + organizationId + '/collections/' + id + '/details', + null, true, true); + return new CollectionGroupDetailsResponse(r); + } + async getCollections(organizationId: string): Promise> { const r = await this.send('GET', '/organizations/' + organizationId + '/collections', null, true, true); return new ListResponse(r, CollectionResponse); } + async getCollectionUsers(organizationId: string, id: string): Promise> { + const r = await this.send('GET', '/organizations/' + organizationId + '/collections/' + id + '/users', + null, true, true); + return new ListResponse(r, CollectionUserResponse); + } + + async postCollection(request: CollectionRequest): Promise { + const r = await this.send('POST', '/collections', request, true, true); + return new CollectionResponse(r); + } + + async putCollection(id: string, request: CollectionRequest): Promise { + const r = await this.send('PUT', '/collections/' + id, request, true, true); + return new CollectionResponse(r); + } + + deleteCollection(id: string): Promise { + return this.send('DELETE', '/collections/' + id, null, true, false); + } + + // Groups APIs + + async getGroupDetails(organizationId: string, id: string): Promise { + const r = await this.send('GET', '/organizations/' + organizationId + '/groups/' + id + '/details', + null, true, true); + return new GroupDetailsResponse(r); + } + + async getGroups(organizationId: string): Promise> { + const r = await this.send('GET', '/organizations/' + organizationId + '/groups', null, true, true); + return new ListResponse(r, GroupResponse); + } + + async getGroupUsers(organizationId: string, id: string): Promise> { + const r = await this.send('GET', '/organizations/' + organizationId + '/groups/' + id + '/users', + null, true, true); + return new ListResponse(r, GroupUserResponse); + } + + async postGroup(request: GroupRequest): Promise { + const r = await this.send('POST', '/groups', request, true, true); + return new GroupResponse(r); + } + + async putGroup(id: string, request: GroupRequest): Promise { + const r = await this.send('PUT', '/groups/' + id, request, true, true); + return new GroupResponse(r); + } + + deleteGroup(id: string): Promise { + return this.send('DELETE', '/groups/' + id, null, true, false); + } + // Sync APIs async getSync(): Promise { diff --git a/src/services/sync.service.ts b/src/services/sync.service.ts index 2e025772c59..07dd66e0032 100644 --- a/src/services/sync.service.ts +++ b/src/services/sync.service.ts @@ -15,7 +15,7 @@ import { FolderData } from '../models/data/folderData'; import { OrganizationData } from '../models/data/organizationData'; import { CipherResponse } from '../models/response/cipherResponse'; -import { CollectionResponse } from '../models/response/collectionResponse'; +import { CollectionDetailsResponse } from '../models/response/collectionResponse'; import { DomainsResponse } from '../models/response/domainsResponse'; import { FolderResponse } from '../models/response/folderResponse'; import { ProfileResponse } from '../models/response/profileResponse'; @@ -162,7 +162,7 @@ export class SyncService implements SyncServiceAbstraction { return await this.folderService.replace(folders); } - private async syncCollections(response: CollectionResponse[]) { + private async syncCollections(response: CollectionDetailsResponse[]) { const collections: { [id: string]: CollectionData; } = {}; response.forEach((c) => { collections[c.id] = new CollectionData(c);