1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-17213] - allow changing of item owner from personal to org (#13034)

* allow changing of item owner from personal to org

* avoid unecessary api calls when updating item parent

* move comment up a line

* add localData to cipher instance
This commit is contained in:
Jordan Aasen
2025-01-23 15:43:42 -08:00
committed by GitHub
parent 382a2a0f24
commit dbb1639e72
5 changed files with 21 additions and 7 deletions

View File

@@ -93,7 +93,7 @@ export abstract class CipherService implements UserKeyRotationDataProvider<Ciphe
organizationId: string, organizationId: string,
collectionIds: string[], collectionIds: string[],
userId: UserId, userId: UserId,
) => Promise<any>; ) => Promise<Cipher>;
shareManyWithServer: ( shareManyWithServer: (
ciphers: CipherView[], ciphers: CipherView[],
organizationId: string, organizationId: string,

View File

@@ -786,7 +786,7 @@ export class CipherService implements CipherServiceAbstraction {
organizationId: string, organizationId: string,
collectionIds: string[], collectionIds: string[],
userId: UserId, userId: UserId,
): Promise<any> { ): Promise<Cipher> {
const attachmentPromises: Promise<any>[] = []; const attachmentPromises: Promise<any>[] = [];
if (cipher.attachments != null) { if (cipher.attachments != null) {
cipher.attachments.forEach((attachment) => { cipher.attachments.forEach((attachment) => {
@@ -806,6 +806,7 @@ export class CipherService implements CipherServiceAbstraction {
const response = await this.apiService.putShareCipher(cipher.id, request); const response = await this.apiService.putShareCipher(cipher.id, request);
const data = new CipherData(response, collectionIds); const data = new CipherData(response, collectionIds);
await this.upsert(data); await this.upsert(data);
return new Cipher(data, cipher.localData);
} }
async shareManyWithServer( async shareManyWithServer(

View File

@@ -157,8 +157,11 @@ describe("ItemDetailsSectionComponent", () => {
}); });
describe("allowOwnershipChange", () => { describe("allowOwnershipChange", () => {
it("should not allow ownership change in edit mode", () => { it("should not allow ownership change if in edit mode and the cipher is owned by an organization", () => {
component.config.mode = "edit"; component.config.mode = "edit";
component.originalCipherView = {
organizationId: "org1",
} as CipherView;
expect(component.allowOwnershipChange).toBe(false); expect(component.allowOwnershipChange).toBe(false);
}); });
@@ -195,6 +198,7 @@ describe("ItemDetailsSectionComponent", () => {
it("should show personal ownership when the configuration allows", () => { it("should show personal ownership when the configuration allows", () => {
component.config.mode = "edit"; component.config.mode = "edit";
component.config.allowPersonalOwnership = true; component.config.allowPersonalOwnership = true;
component.originalCipherView = {} as CipherView;
component.config.organizations = [{ id: "134-433-22" } as Organization]; component.config.organizations = [{ id: "134-433-22" } as Organization];
fixture.detectChanges(); fixture.detectChanges();
@@ -208,6 +212,7 @@ describe("ItemDetailsSectionComponent", () => {
it("should show personal ownership when the control is disabled", async () => { it("should show personal ownership when the control is disabled", async () => {
component.config.mode = "edit"; component.config.mode = "edit";
component.config.allowPersonalOwnership = false; component.config.allowPersonalOwnership = false;
component.originalCipherView = {} as CipherView;
component.config.organizations = [{ id: "134-433-22" } as Organization]; component.config.organizations = [{ id: "134-433-22" } as Organization];
await component.ngOnInit(); await component.ngOnInit();
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -150,8 +150,8 @@ export class ItemDetailsSectionComponent implements OnInit {
} }
get allowOwnershipChange() { get allowOwnershipChange() {
// Do not allow ownership change in edit mode. // Do not allow ownership change in edit mode and the cipher is owned by an organization
if (this.config.mode === "edit") { if (this.config.mode === "edit" && this.originalCipherView.organizationId != null) {
return false; return false;
} }

View File

@@ -63,8 +63,16 @@ export class DefaultCipherFormService implements CipherFormService {
const originalCollectionIds = new Set(config.originalCipher.collectionIds ?? []); const originalCollectionIds = new Set(config.originalCipher.collectionIds ?? []);
const newCollectionIds = new Set(cipher.collectionIds ?? []); const newCollectionIds = new Set(cipher.collectionIds ?? []);
// If the collectionIds are the same, update the cipher normally // Call shareWithServer if the owner is changing from a user to an organization
if (isSetEqual(originalCollectionIds, newCollectionIds)) { if (config.originalCipher.organizationId === null && cipher.organizationId != null) {
savedCipher = await this.cipherService.shareWithServer(
cipher,
cipher.organizationId,
cipher.collectionIds,
activeUserId,
);
// If the collectionIds are the same, update the cipher normally
} else if (isSetEqual(originalCollectionIds, newCollectionIds)) {
savedCipher = await this.cipherService.updateWithServer(encryptedCipher, config.admin); savedCipher = await this.cipherService.updateWithServer(encryptedCipher, config.admin);
} else { } else {
// Updating a cipher with collection changes is not supported with a single request currently // Updating a cipher with collection changes is not supported with a single request currently