1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00
Files
browser/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-people.component.ts
Thomas Avery c711312fee [SM-581] User access removal warnings (#4904)
* init refactor

* Fix current user access checks

* Add in warning dialogs that are aware of other APs

* cleanup handlers; refresh sa list on removal

* Code review updates

* [SM-580] Add warning dialog for Service account People tab (#4893)

* Add warning dialog from figma

* move dialog out of access selector component; add after delete event; remove people-sa logic

* remove commented code and unused service

* Updates to work with SM-581

---------

Co-authored-by: William Martin <contact@willmartian.com>

---------

Co-authored-by: William Martin <contact@willmartian.com>
2023-03-06 11:32:02 -06:00

193 lines
5.9 KiB
TypeScript

import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { map, Observable, share, startWith, Subject, switchMap, takeUntil } from "rxjs";
import { ValidationService } from "@bitwarden/common/abstractions/validation.service";
import { DialogService, SelectItemView } from "@bitwarden/components";
import {
GroupProjectAccessPolicyView,
ProjectAccessPoliciesView,
UserProjectAccessPolicyView,
} from "../../models/view/access-policy.view";
import { AccessPolicyService } from "../../shared/access-policies/access-policy.service";
import {
AccessSelectorComponent,
AccessSelectorRowView,
} from "../../shared/access-policies/access-selector.component";
import {
AccessRemovalDetails,
AccessRemovalDialogComponent,
} from "../../shared/access-policies/dialogs/access-removal-dialog.component";
@Component({
selector: "sm-project-people",
templateUrl: "./project-people.component.html",
})
export class ProjectPeopleComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
private organizationId: string;
private projectId: string;
private rows: AccessSelectorRowView[];
protected rows$: Observable<AccessSelectorRowView[]> =
this.accessPolicyService.projectAccessPolicyChanges$.pipe(
startWith(null),
switchMap(() =>
this.accessPolicyService.getProjectAccessPolicies(this.organizationId, this.projectId)
),
map((policies) => {
const rows: AccessSelectorRowView[] = [];
policies.userAccessPolicies.forEach((policy) => {
rows.push({
type: "user",
name: policy.organizationUserName,
id: policy.organizationUserId,
accessPolicyId: policy.id,
read: policy.read,
write: policy.write,
userId: policy.userId,
icon: AccessSelectorComponent.userIcon,
});
});
policies.groupAccessPolicies.forEach((policy) => {
rows.push({
type: "group",
name: policy.groupName,
id: policy.groupId,
accessPolicyId: policy.id,
read: policy.read,
write: policy.write,
currentUserInGroup: policy.currentUserInGroup,
icon: AccessSelectorComponent.groupIcon,
});
});
return rows;
}),
share()
);
protected handleCreateAccessPolicies(selected: SelectItemView[]) {
const projectAccessPoliciesView = new ProjectAccessPoliciesView();
projectAccessPoliciesView.userAccessPolicies = selected
.filter((selection) => AccessSelectorComponent.getAccessItemType(selection) === "user")
.map((filtered) => {
const view = new UserProjectAccessPolicyView();
view.grantedProjectId = this.projectId;
view.organizationUserId = filtered.id;
view.read = true;
view.write = false;
return view;
});
projectAccessPoliciesView.groupAccessPolicies = selected
.filter((selection) => AccessSelectorComponent.getAccessItemType(selection) === "group")
.map((filtered) => {
const view = new GroupProjectAccessPolicyView();
view.grantedProjectId = this.projectId;
view.groupId = filtered.id;
view.read = true;
view.write = false;
return view;
});
return this.accessPolicyService.createProjectAccessPolicies(
this.organizationId,
this.projectId,
projectAccessPoliciesView
);
}
protected async handleDeleteAccessPolicy(policy: AccessSelectorRowView) {
if (
await this.accessPolicyService.needToShowAccessRemovalWarning(
this.organizationId,
policy,
this.rows
)
) {
this.launchDeleteWarningDialog(policy);
return;
}
try {
await this.accessPolicyService.deleteAccessPolicy(policy.accessPolicyId);
} catch (e) {
this.validationService.showError(e);
}
}
protected async handleUpdateAccessPolicy(policy: AccessSelectorRowView) {
if (
policy.read === true &&
policy.write === false &&
(await this.accessPolicyService.needToShowAccessRemovalWarning(
this.organizationId,
policy,
this.rows
))
) {
this.launchUpdateWarningDialog(policy);
return;
}
try {
return await this.accessPolicyService.updateAccessPolicy(
AccessSelectorComponent.getBaseAccessPolicyView(policy)
);
} catch (e) {
this.validationService.showError(e);
}
}
constructor(
private route: ActivatedRoute,
private dialogService: DialogService,
private validationService: ValidationService,
private accessPolicyService: AccessPolicyService
) {}
ngOnInit(): void {
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
this.organizationId = params.organizationId;
this.projectId = params.projectId;
});
this.rows$.pipe(takeUntil(this.destroy$)).subscribe((rows) => {
this.rows = rows;
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
private async launchDeleteWarningDialog(policy: AccessSelectorRowView) {
this.dialogService.open<unknown, AccessRemovalDetails>(AccessRemovalDialogComponent, {
data: {
title: "smAccessRemovalWarningProjectTitle",
message: "smAccessRemovalWarningProjectMessage",
operation: "delete",
type: "project",
returnRoute: ["sm", this.organizationId, "projects"],
policy,
},
});
}
private launchUpdateWarningDialog(policy: AccessSelectorRowView) {
this.dialogService.open<unknown, AccessRemovalDetails>(AccessRemovalDialogComponent, {
data: {
title: "smAccessRemovalWarningProjectTitle",
message: "smAccessRemovalWarningProjectMessage",
operation: "update",
type: "project",
returnRoute: ["sm", this.organizationId, "projects"],
policy,
},
});
}
}