From 3e3583269eeb39aa9ddc16b79bc644d3a1badd7e Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Tue, 11 Oct 2022 11:55:38 -0700 Subject: [PATCH] [EC-86] Add GroupApiService Add a new GroupApiService to replace Group Api calls in the ApiService. --- .../manage/collection-add-edit.component.ts | 5 +- .../manage/group-add-edit.component.ts | 6 +- .../organizations/manage/groups.component.ts | 15 +++-- .../manage/user-groups.component.ts | 5 +- .../src/services/jslib-services.module.ts | 19 ++++-- libs/common/src/abstractions/api.service.ts | 12 +--- .../group/group-api.service.abstraction.ts | 13 ++++ libs/common/src/abstractions/group/index.ts | 2 + .../group/responses}/groupResponse.ts | 4 +- libs/common/src/services/api.service.ts | 50 +--------------- .../src/services/group/group-api.service.ts | 60 +++++++++++++++++++ 11 files changed, 112 insertions(+), 79 deletions(-) create mode 100644 libs/common/src/abstractions/group/group-api.service.abstraction.ts create mode 100644 libs/common/src/abstractions/group/index.ts rename libs/common/src/{models/response => abstractions/group/responses}/groupResponse.ts (83%) create mode 100644 libs/common/src/services/group/group-api.service.ts diff --git a/apps/web/src/app/organizations/manage/collection-add-edit.component.ts b/apps/web/src/app/organizations/manage/collection-add-edit.component.ts index 5c428abda4f..11fea20e68c 100644 --- a/apps/web/src/app/organizations/manage/collection-add-edit.component.ts +++ b/apps/web/src/app/organizations/manage/collection-add-edit.component.ts @@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { GroupApiServiceAbstraction, GroupResponse } from "@bitwarden/common/abstractions/group"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; @@ -11,7 +12,6 @@ import { EncString } from "@bitwarden/common/models/domain/encString"; import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey"; import { CollectionRequest } from "@bitwarden/common/models/request/collectionRequest"; import { SelectionReadOnlyRequest } from "@bitwarden/common/models/request/selectionReadOnlyRequest"; -import { GroupResponse } from "@bitwarden/common/models/response/groupResponse"; @Component({ selector: "app-collection-add-edit", @@ -39,6 +39,7 @@ export class CollectionAddEditComponent implements OnInit { constructor( private apiService: ApiService, + private groupApiService: GroupApiServiceAbstraction, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private cryptoService: CryptoService, @@ -51,7 +52,7 @@ export class CollectionAddEditComponent implements OnInit { this.accessGroups = organization.useGroups; this.editMode = this.loading = this.collectionId != null; if (this.accessGroups) { - const groupsResponse = await this.apiService.getGroups(this.organizationId); + const groupsResponse = await this.groupApiService.getAll(this.organizationId); this.groups = groupsResponse.data .map((r) => r) .sort(Utils.getSortFunction(this.i18nService, "name")); diff --git a/apps/web/src/app/organizations/manage/group-add-edit.component.ts b/apps/web/src/app/organizations/manage/group-add-edit.component.ts index 0d5f654a505..e8c18d81a05 100644 --- a/apps/web/src/app/organizations/manage/group-add-edit.component.ts +++ b/apps/web/src/app/organizations/manage/group-add-edit.component.ts @@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { GroupApiServiceAbstraction } from "@bitwarden/common/abstractions/group"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -34,6 +35,7 @@ export class GroupAddEditComponent implements OnInit { constructor( private apiService: ApiService, + private groupApiService: GroupApiServiceAbstraction, private i18nService: I18nService, private collectionService: CollectionService, private platformUtilsService: PlatformUtilsService, @@ -48,7 +50,7 @@ export class GroupAddEditComponent implements OnInit { this.editMode = true; this.title = this.i18nService.t("editGroup"); try { - const group = await this.apiService.getGroupDetails(this.organizationId, this.groupId); + const group = await this.groupApiService.get(this.organizationId, this.groupId); this.access = group.accessAll ? "all" : "selected"; this.name = group.name; this.externalId = group.externalId; @@ -137,7 +139,7 @@ export class GroupAddEditComponent implements OnInit { } try { - this.deletePromise = this.apiService.deleteGroup(this.organizationId, this.groupId); + this.deletePromise = this.groupApiService.delete(this.organizationId, this.groupId); await this.deletePromise; this.platformUtilsService.showToast( "success", diff --git a/apps/web/src/app/organizations/manage/groups.component.ts b/apps/web/src/app/organizations/manage/groups.component.ts index 9d75c531506..163c6cc6773 100644 --- a/apps/web/src/app/organizations/manage/groups.component.ts +++ b/apps/web/src/app/organizations/manage/groups.component.ts @@ -17,6 +17,10 @@ import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { + GroupApiServiceAbstraction, + GroupDetailsResponse, +} from "@bitwarden/common/abstractions/group"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -24,12 +28,10 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { CollectionData } from "@bitwarden/common/models/data/collectionData"; import { Collection } from "@bitwarden/common/models/domain/collection"; -import { OrganizationGroupBulkRequest } from "@bitwarden/common/models/request/OrganizationGroupBulkRequest"; import { CollectionDetailsResponse, CollectionResponse, } from "@bitwarden/common/models/response/collectionResponse"; -import { GroupDetailsResponse } from "@bitwarden/common/models/response/groupResponse"; import { ListResponse } from "@bitwarden/common/models/response/listResponse"; import { CollectionView } from "@bitwarden/common/models/view/collectionView"; @@ -106,6 +108,7 @@ export class GroupsComponent implements OnInit, OnDestroy { constructor( private apiService: ApiService, + private groupApiService: GroupApiServiceAbstraction, private route: ActivatedRoute, private i18nService: I18nService, private modalService: ModalService, @@ -128,7 +131,7 @@ export class GroupsComponent implements OnInit, OnDestroy { ), // groups this.refreshGroups$.pipe( - switchMap(() => this.apiService.getGroups(this.organizationId)), + switchMap(() => this.groupApiService.getAll(this.organizationId)), map((response) => response.data != null && response.data.length > 0 ? response.data : [] ) @@ -225,7 +228,7 @@ export class GroupsComponent implements OnInit, OnDestroy { } try { - await this.apiService.deleteGroup(this.organizationId, groupRow.details.id); + await this.groupApiService.delete(this.organizationId, groupRow.details.id); this.platformUtilsService.showToast( "success", null, @@ -257,9 +260,9 @@ export class GroupsComponent implements OnInit, OnDestroy { } try { - const result = await this.apiService.deleteManyGroups( + const result = await this.groupApiService.deleteMany( this.organizationId, - new OrganizationGroupBulkRequest(groupsToDelete.map((g) => g.details.id)) + groupsToDelete.map((g) => g.details.id) ); this.platformUtilsService.showToast( "success", diff --git a/apps/web/src/app/organizations/manage/user-groups.component.ts b/apps/web/src/app/organizations/manage/user-groups.component.ts index baacade7577..eab60767725 100644 --- a/apps/web/src/app/organizations/manage/user-groups.component.ts +++ b/apps/web/src/app/organizations/manage/user-groups.component.ts @@ -1,12 +1,12 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { GroupApiServiceAbstraction, GroupResponse } from "@bitwarden/common/abstractions/group"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { OrganizationUserUpdateGroupsRequest } from "@bitwarden/common/models/request/organizationUserUpdateGroupsRequest"; -import { GroupResponse } from "@bitwarden/common/models/response/groupResponse"; @Component({ selector: "app-user-groups", @@ -24,13 +24,14 @@ export class UserGroupsComponent implements OnInit { constructor( private apiService: ApiService, + private groupApiService: GroupApiServiceAbstraction, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private logService: LogService ) {} async ngOnInit() { - const groupsResponse = await this.apiService.getGroups(this.organizationId); + const groupsResponse = await this.groupApiService.getAll(this.organizationId); const groups = groupsResponse.data.map((r) => r); groups.sort(Utils.getSortFunction(this.i18nService, "name")); this.groups = groups; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 213f5617497..cfc6e46d2f2 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -27,6 +27,7 @@ import { InternalFolderService, } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service"; +import { GroupApiServiceAbstraction } from "@bitwarden/common/abstractions/group"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/abstractions/keyConnector.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -39,8 +40,8 @@ import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@ import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction"; import { - PolicyService as PolicyServiceAbstraction, InternalPolicyService, + PolicyService as PolicyServiceAbstraction, } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/abstractions/provider.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; @@ -83,6 +84,7 @@ import { FileUploadService } from "@bitwarden/common/services/fileUpload.service import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/services/folder/folder.service"; import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service"; +import { GroupApiService } from "@bitwarden/common/services/group/group-api.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { OrganizationApiService } from "@bitwarden/common/services/organization/organization-api.service"; @@ -114,16 +116,16 @@ import { UnauthGuard } from "../guards/unauth.guard"; import { BroadcasterService } from "./broadcaster.service"; import { - WINDOW, + LOCALES_DIRECTORY, + LOCKED_CALLBACK, + LOG_MAC_FAILURES, + LOGOUT_CALLBACK, MEMORY_STORAGE, SECURE_STORAGE, STATE_FACTORY, STATE_SERVICE_USE_CACHE, - LOGOUT_CALLBACK, - LOCKED_CALLBACK, - LOCALES_DIRECTORY, SYSTEM_LANGUAGE, - LOG_MAC_FAILURES, + WINDOW, } from "./injection-tokens"; import { ModalService } from "./modal.service"; import { PasswordRepromptService } from "./passwordReprompt.service"; @@ -561,6 +563,11 @@ import { ValidationService } from "./validation.service"; useClass: AnonymousHubService, deps: [EnvironmentServiceAbstraction, AuthServiceAbstraction, LogService], }, + { + provide: GroupApiServiceAbstraction, + useClass: GroupApiService, + deps: [ApiServiceAbstraction], + }, ], }) export class JslibServicesModule {} diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index e6e639b66e5..eb3339b8adc 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -1,5 +1,3 @@ -import { OrganizationGroupBulkRequest } from "@bitwarden/common/models/request/OrganizationGroupBulkRequest"; - import { OrganizationConnectionType } from "../enums/organizationConnectionType"; import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest"; import { AttachmentRequest } from "../models/request/attachmentRequest"; @@ -106,7 +104,6 @@ import { EmergencyAccessViewResponse, } from "../models/response/emergencyAccessResponse"; import { EventResponse } from "../models/response/eventResponse"; -import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse"; import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse"; import { IdentityTokenResponse } from "../models/response/identityTokenResponse"; import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse"; @@ -164,6 +161,8 @@ import { TwoFactorYubiKeyResponse } from "../models/response/twoFactorYubiKeyRes import { UserKeyResponse } from "../models/response/userKeyResponse"; import { SendAccessView } from "../models/view/sendAccessView"; +import { GroupResponse } from "./group/responses/groupResponse"; + export abstract class ApiService { send: ( method: "GET" | "POST" | "PUT" | "DELETE", @@ -341,17 +340,10 @@ export abstract class ApiService { organizationUserId: string ) => Promise; - getGroupDetails: (organizationId: string, id: string) => Promise; - getGroups: (organizationId: string) => Promise>; getGroupUsers: (organizationId: string, id: string) => Promise; postGroup: (organizationId: string, request: GroupRequest) => Promise; putGroup: (organizationId: string, id: string, request: GroupRequest) => Promise; putGroupUsers: (organizationId: string, id: string, request: string[]) => Promise; - deleteGroup: (organizationId: string, id: string) => Promise; - deleteManyGroups: ( - organizationId: string, - request: OrganizationGroupBulkRequest - ) => Promise>; deleteGroupUser: (organizationId: string, id: string, organizationUserId: string) => Promise; getOrganizationUser: ( diff --git a/libs/common/src/abstractions/group/group-api.service.abstraction.ts b/libs/common/src/abstractions/group/group-api.service.abstraction.ts new file mode 100644 index 00000000000..da5a6ccfff3 --- /dev/null +++ b/libs/common/src/abstractions/group/group-api.service.abstraction.ts @@ -0,0 +1,13 @@ +import { + GroupDetailsResponse, + GroupResponse, +} from "@bitwarden/common/abstractions/group/responses/groupResponse"; +import { ListResponse } from "@bitwarden/common/models/response/listResponse"; + +export class GroupApiServiceAbstraction { + delete: (orgId: string, groupId: string) => Promise; + deleteMany: (orgId: string, groupIds: string[]) => Promise>; + + get: (orgId: string, groupId: string) => Promise; + getAll: (orgId: string) => Promise>; +} diff --git a/libs/common/src/abstractions/group/index.ts b/libs/common/src/abstractions/group/index.ts new file mode 100644 index 00000000000..e4e5a86719d --- /dev/null +++ b/libs/common/src/abstractions/group/index.ts @@ -0,0 +1,2 @@ +export * from "./group-api.service.abstraction"; +export * from "./responses/groupResponse"; diff --git a/libs/common/src/models/response/groupResponse.ts b/libs/common/src/abstractions/group/responses/groupResponse.ts similarity index 83% rename from libs/common/src/models/response/groupResponse.ts rename to libs/common/src/abstractions/group/responses/groupResponse.ts index ab4b58b7b55..b7690d1358c 100644 --- a/libs/common/src/models/response/groupResponse.ts +++ b/libs/common/src/abstractions/group/responses/groupResponse.ts @@ -1,5 +1,5 @@ -import { BaseResponse } from "./baseResponse"; -import { SelectionReadOnlyResponse } from "./selectionReadOnlyResponse"; +import { BaseResponse } from "../../../models/response/baseResponse"; +import { SelectionReadOnlyResponse } from "../../../models/response/selectionReadOnlyResponse"; export class GroupResponse extends BaseResponse { id: string; diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index f8e190fa429..ae4afdbfda1 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -1,8 +1,7 @@ -import { OrganizationGroupBulkRequest } from "@bitwarden/common/models/request/OrganizationGroupBulkRequest"; - import { ApiService as ApiServiceAbstraction } from "../abstractions/api.service"; import { AppIdService } from "../abstractions/appId.service"; import { EnvironmentService } from "../abstractions/environment.service"; +import { GroupResponse } from "../abstractions/group"; import { PlatformUtilsService } from "../abstractions/platformUtils.service"; import { TokenService } from "../abstractions/token.service"; import { DeviceType } from "../enums/deviceType"; @@ -115,7 +114,6 @@ import { } from "../models/response/emergencyAccessResponse"; import { ErrorResponse } from "../models/response/errorResponse"; import { EventResponse } from "../models/response/eventResponse"; -import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse"; import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse"; import { IdentityTokenResponse } from "../models/response/identityTokenResponse"; import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse"; @@ -922,28 +920,6 @@ export class ApiService implements ApiServiceAbstraction { // 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, GroupDetailsResponse); - } - async getGroupUsers(organizationId: string, id: string): Promise { const r = await this.send( "GET", @@ -991,30 +967,6 @@ export class ApiService implements ApiServiceAbstraction { ); } - deleteGroup(organizationId: string, id: string): Promise { - return this.send( - "DELETE", - "/organizations/" + organizationId + "/groups/" + id, - null, - true, - false - ); - } - - async deleteManyGroups( - organizationId: string, - request: OrganizationGroupBulkRequest - ): Promise> { - const r = await this.send( - "DELETE", - "/organizations/" + organizationId + "/groups", - request, - true, - true - ); - return new ListResponse(r, GroupResponse); - } - deleteGroupUser(organizationId: string, id: string, organizationUserId: string): Promise { return this.send( "DELETE", diff --git a/libs/common/src/services/group/group-api.service.ts b/libs/common/src/services/group/group-api.service.ts new file mode 100644 index 00000000000..5493f64f3c9 --- /dev/null +++ b/libs/common/src/services/group/group-api.service.ts @@ -0,0 +1,60 @@ +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { + GroupApiServiceAbstraction, + GroupDetailsResponse, + GroupResponse, +} from "@bitwarden/common/abstractions/group"; +import { OrganizationGroupBulkRequest } from "@bitwarden/common/models/request/OrganizationGroupBulkRequest"; +import { ListResponse } from "@bitwarden/common/models/response/listResponse"; + +export class GroupApiService implements GroupApiServiceAbstraction { + constructor(private apiService: ApiService) {} + + async delete(orgId: string, groupId: string): Promise { + await this.apiService.send( + "DELETE", + "/organizations/" + orgId + "/groups/" + groupId, + null, + true, + false + ); + } + + async deleteMany(orgId: string, groupIds: string[]): Promise> { + const request = new OrganizationGroupBulkRequest(groupIds); + + const r = await this.apiService.send( + "DELETE", + "/organizations/" + orgId + "/groups", + request, + true, + true + ); + + return new ListResponse(r, GroupResponse); + } + + async get(orgId: string, groupId: string): Promise { + const r = await this.apiService.send( + "GET", + "/organizations/" + orgId + "/groups/" + groupId + "/details", + null, + true, + true + ); + + return new GroupDetailsResponse(r); + } + + async getAll(orgId: string): Promise> { + const r = await this.apiService.send( + "GET", + "/organizations/" + orgId + "/groups", + null, + true, + true + ); + + return new ListResponse(r, GroupDetailsResponse); + } +}