[ACA-2864] Site Managers are not able to disable inherit permissions … (#7021)

* [ACA-2864] Site Managers are not able to disable inherit permissions in DW/ACA

* * added test cases

* * fixed lints

* * [force ci] remove mispell
This commit is contained in:
Dharan
2021-05-14 18:42:57 +05:30
committed by GitHub
parent 81042f1951
commit 65e3a21c25
7 changed files with 190 additions and 14 deletions

View File

@@ -124,7 +124,8 @@ export const fakeNodeInheritedOnly = {
},
{
'id': 'e002c740-b8f9-482a-a554-8fff4e4c9dc0',
'name': 'testsite'
'name': 'testsite',
'nodeType': 'st:site'
},
{
'id': '71626fae-0c04-4d0c-a129-20fa4c178716',
@@ -579,3 +580,83 @@ export const fakeEmptyResponse: any = {
'entries': []
}
};
export const fakeNodeLocalSiteManager = {
'allowableOperations': [ 'updatePermissions' ],
'aspectNames': [
'cm:auditable',
'cm:taggable',
'cm:author',
'cm:titled',
'app:uifacets'
],
'createdAt': '2017-11-16T16:29:38.638+0000',
'path': {
'name': '/Company Home/Sites/testsite/documentLibrary',
'isComplete': true,
'elements': [
{
'id': '2be275a1-b00d-4e45-83d8-66af43ac2252',
'name': 'Company Home'
},
{
'id': '1be10a97-6eb9-4b60-b6c6-1673900e9631',
'name': 'Sites'
},
{
'id': 'e002c740-b8f9-482a-a554-8fff4e4c9dc0',
'name': 'testsite',
'nodeType': 'st:site'
},
{
'id': '71626fae-0c04-4d0c-a129-20fa4c178716',
'name': 'documentLibrary'
}
]
},
'isFolder': true,
'isFile': false,
'createdByUser': {
'id': 'System',
'displayName': 'System'
},
'modifiedAt': '2018-03-21T03:17:58.783+0000',
'permissions': {
'locallySet': [
{
'authorityId': 'GROUP_site_testsite_SiteManager',
'name': 'SiteManager',
'accessStatus': 'ALLOWED'
},
{
'authorityId': 'superadminuser',
'name': 'SiteCollaborator',
'accessStatus': 'ALLOWED'
}
],
'settable': [
'Contributor',
'Collaborator',
'Coordinator',
'Editor',
'Consumer'
],
'isInheritanceEnabled': false
},
'modifiedByUser': {
'id': 'admin',
'displayName': 'PedroH Hernandez'
},
'name': 'test',
'id': 'f472543f-7218-403d-917b-7a5861257244',
'nodeType': 'cm:folder',
'properties': {
'cm:title': 'test',
'cm:author': 'yagud',
'cm:taggable': [
'e8c8fbba-03ba-4fa6-86b1-f7ad7c296409'
],
'cm:description': 'sleepery',
'app:icon': 'space-icon-default'
}
};

View File

@@ -34,7 +34,7 @@
key="name"
sortable="false">
<ng-template let-entry="$implicit">
<adf-user-role-column [readonly]="isReadOnly"
<adf-user-role-column [readonly]="entry.row.obj.readonly || isReadOnly"
[placeholder]="entry.data.getValue(entry.row, entry.col)"
[value]="entry.data.getValue(entry.row, entry.col)"
[roles]="roles"
@@ -59,6 +59,7 @@
<data-column class="adf-datatable-cell adf-delete-permission-column" key="" *ngIf="!isReadOnly" [sortable]="false">
<ng-template let-entry="$implicit">
<button mat-icon-button
[disabled]="entry.row.obj.readonly"
(click)="removePermission($event, entry.row.obj)"
[attr.data-automation-id]="'adf-delete-permission-button-' + entry.row.obj.authorityId">
<mat-icon>delete_outline</mat-icon>

View File

@@ -25,6 +25,7 @@ import { NodePermissionService } from '../../services/node-permission.service';
import {
fakeEmptyResponse,
fakeNodeInheritedOnly,
fakeNodeLocalSiteManager,
fakeNodeWithOnlyLocally,
fakeNodeWithoutPermissions,
fakeNodeWithPermissions,
@@ -206,6 +207,19 @@ describe('PermissionListComponent', () => {
expect(options[3].nativeElement.innerText).toContain('ADF.ROLES.SITEMANAGER');
});
it('should show readonly member for site manager to toggle the inherit permission', async() => {
getNodeSpy.and.returnValue(of(fakeNodeLocalSiteManager));
component.ngOnInit();
await fixture.detectChanges();
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_site_testsite_SiteManager');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('ADF.ROLES.SITEMANAGER');
const deleteButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-GROUP_site_testsite_SiteManager"]');
expect(deleteButton.disabled).toBe(true);
const otherDeleteButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-superadminuser"]');
expect(otherDeleteButton.disabled).toBe(false);
});
it('should update the role when another value is chosen', async () => {
spyOn(nodeService, 'updateNode').and.returnValue(of({id: 'fake-uwpdated-node'}));
searchQuerySpy.and.returnValue(of(fakeEmptyResponse));
@@ -236,8 +250,8 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor');
const showButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]');
showButton.click();
const deleteButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]');
deleteButton.click();
fixture.detectChanges();
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', { permissions: { locallySet: [ ] } });

View File

@@ -56,7 +56,7 @@ export class PermissionListComponent {
}
onSelect(selections: ObjectDataRow[]) {
this.selectedPermissions = selections.map((selection) => selection['obj']);
this.selectedPermissions = selections.map((selection) => selection['obj']).filter((permission) => !permission.readonly);
}
deleteSelection() {

View File

@@ -22,7 +22,7 @@ import { of, throwError } from 'rxjs';
import { PermissionListService } from './permission-list.service';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { NodePermissionService } from '../../services/node-permission.service';
import { fakeNodeInheritedOnly, fakeNodeWithOnlyLocally } from '../../../mock/permission-list.component.mock';
import { fakeNodeInheritedOnly, fakeNodeLocalSiteManager, fakeNodeWithOnlyLocally } from '../../../mock/permission-list.component.mock';
import { PermissionDisplayModel } from '../../models/permission.model';
describe('PermissionListService', () => {
@@ -82,21 +82,50 @@ describe('PermissionListService', () => {
expect(notificationService.showError).toHaveBeenCalledWith('PERMISSION_MANAGER.ERROR.NOT-ALLOWED');
});
it('should show message after success toggle', () => {
it('should include the local permission before toggle', (done) => {
const node = JSON.parse(JSON.stringify(fakeNodeInheritedOnly)), event = { source: { checked: false } };
spyOn(nodePermissionService, 'getNodeWithRoles').and.returnValue(of({node , roles: []}));
spyOn(nodePermissionService, 'updatePermissions').and.returnValue(of(null));
spyOn(nodesApiService, 'updateNode').and.returnValue(of(JSON.parse(JSON.stringify(fakeNodeLocalSiteManager))));
service.fetchPermission('fetch node');
const subscription = service.data$.subscribe(({ localPermissions }) => {
expect(localPermissions[0].authorityId).toBe('GROUP_site_testsite_SiteManager');
expect(localPermissions[0].readonly).toBe(true);
expect(localPermissions[1].authorityId).toBe('superadminuser');
expect(localPermissions[1].readonly).toBe(undefined);
expect(nodePermissionService.updatePermissions).toHaveBeenCalled();
expect(nodesApiService.updateNode).toHaveBeenCalled();
expect(notificationService.showInfo).toHaveBeenCalledWith('PERMISSION_MANAGER.MESSAGE.INHERIT-DISABLE-SUCCESS');
subscription.unsubscribe();
done();
});
service.toggleInherited(event as any);
});
it('should not update local permission before toggle', () => {
const node = JSON.parse(JSON.stringify(fakeNodeInheritedOnly)), event = { source: { checked: false } };
const updateNode = JSON.parse(JSON.stringify(fakeNodeInheritedOnly));
node.permissions.locallySet = [{
'authorityId': 'GROUP_site_testsite_SiteManager',
'name': 'SiteManager',
'accessStatus': 'ALLOWED'
}];
updateNode.permissions.isInheritanceEnabled = false;
spyOn(nodePermissionService, 'getNodeWithRoles').and.returnValue(of({node , roles: []}));
spyOn(nodePermissionService, 'updatePermissions').and.returnValue(of(null));
spyOn(nodesApiService, 'updateNode').and.returnValue(of(updateNode));
service.fetchPermission('fetch node');
service.toggleInherited(event as any);
expect(nodePermissionService.updatePermissions).not.toHaveBeenCalled();
expect(nodesApiService.updateNode).toHaveBeenCalled();
expect(notificationService.showInfo).toHaveBeenCalledWith('PERMISSION_MANAGER.MESSAGE.INHERIT-DISABLE-SUCCESS');
});
it('should show message for errored toggle', () => {
const node = JSON.parse(JSON.stringify(fakeNodeInheritedOnly)), event = { source: { checked: false } };
node.permissions.isInheritanceEnabled = true;
spyOn(nodesApiService, 'updateNode').and.returnValue(throwError('Failed to update'));
spyOn(nodePermissionService, 'getNodeWithRoles').and.returnValue(of({node , roles: []}));
service.fetchPermission('fetch node');
@@ -104,6 +133,7 @@ describe('PermissionListService', () => {
service.toggleInherited(event as any);
expect(nodesApiService.updateNode).toHaveBeenCalled();
expect(notificationService.showWarning).toHaveBeenCalledWith('PERMISSION_MANAGER.MESSAGE.TOGGLE-PERMISSION-FAILED');
expect(event.source.checked).toEqual(true);
});
});

View File

@@ -39,18 +39,20 @@ export class PermissionListService {
nodeWithRoles$: Subject<{ node: Node, roles: RoleModel[] }> = new Subject();
data$: Observable<NodePermissionsModel> = this.nodeWithRoles$.pipe(
map(({ node, roles}) => {
const nodeLocalPermissions = this.nodePermissionService.getLocalPermissions(node);
const localPermissions = this.updateReadOnlyPermission(node, nodeLocalPermissions);
return {
node,
roles,
inheritedPermissions: this.nodePermissionService.getInheritedPermission(node),
localPermissions: this.nodePermissionService.getLocalPermissions(node),
allPermission: this.nodePermissionService.getNodePermissions(node)
localPermissions,
inheritedPermissions: this.nodePermissionService.getInheritedPermission(node)
};
})
);
private node: Node;
private roles: RoleModel[];
private SITE_MANAGER_ROLE = 'SiteManager';
constructor(
private nodeService: NodesApiService,
@@ -76,12 +78,23 @@ export class PermissionListService {
toggleInherited(change: MatSlideToggleChange) {
if (this.contentService.hasAllowableOperations(this.node, AllowableOperationsEnum.UPDATEPERMISSIONS)) {
let updateLocalPermission$ = of(null);
const nodeBody = {
permissions: {
isInheritanceEnabled: !this.node.permissions.isInheritanceEnabled
}
};
this.nodeService.updateNode(this.node.id, nodeBody, {include: ['permissions']})
const authorityId = this.getManagerAuthority(this.node);
if (authorityId) {
const permissions = [
...(this.node.permissions.locallySet || []),
{ authorityId, name: this.SITE_MANAGER_ROLE, accessStatus: 'ALLOWED' }
];
updateLocalPermission$ = this.nodePermissionService.updatePermissions(this.node, permissions);
}
updateLocalPermission$.pipe(switchMap(() => this.nodeService.updateNode(this.node.id, nodeBody, {include: ['permissions']})))
.subscribe(
(nodeUpdated: Node) => {
const message = nodeUpdated.permissions.isInheritanceEnabled ? 'PERMISSION_MANAGER.MESSAGE.INHERIT-ENABLE-SUCCESS' : 'PERMISSION_MANAGER.MESSAGE.INHERIT-DISABLE-SUCCESS';
@@ -157,7 +170,7 @@ export class PermissionListService {
}
bulkRoleUpdate(role: string) {
const permissions = [...this.node.permissions.locallySet] .map((permission) => this.buildUpdatedPermission(role, permission));
const permissions = [...this.node.permissions.locallySet].map((permission) => this.buildUpdatedPermission(role, permission));
this.nodePermissionService.updatePermissions(this.node, permissions)
.subscribe((node) => {
const total = permissions.length;
@@ -173,10 +186,14 @@ export class PermissionListService {
}
deletePermission(permission: PermissionDisplayModel) {
const cloneNode = { ...this.node, permissions: { ...this.node.permissions, locallySet: [ ...this.node.permissions.locallySet ] } };
this.nodePermissionService
.removePermission(this.node, permission)
.removePermission(cloneNode, permission)
.subscribe((node) => {
this.notificationService.showInfo('PERMISSION_MANAGER.MESSAGE.PERMISSION-DELETE-SUCCESS');
if (!node.permissions.locallySet) {
node.permissions.locallySet = [];
}
this.reloadNode(node);
},
() => {
@@ -189,7 +206,7 @@ export class PermissionListService {
private buildUpdatedPermission(role: string, permission: PermissionElement): PermissionElement {
return {
accessStatus: permission.accessStatus,
name: role,
name: this.canUpdateThePermission(this.node, permission) ? role : permission.name,
authorityId: permission.authorityId
};
}
@@ -201,6 +218,38 @@ export class PermissionListService {
this.nodeWithRoles$.next({ node: this.node, roles: this.roles });
}
getManagerAuthority(node: Node): string {
const sitePath = node.path.elements.find((path) => path.nodeType === 'st:site');
let hasLocalManagerPermission = false, authorityId: string;
if (sitePath) {
authorityId = `GROUP_site_${sitePath.name}_${this.SITE_MANAGER_ROLE}`;
hasLocalManagerPermission = !!node.permissions.locallySet?.find((permission) => permission.authorityId === authorityId && permission.name === this.SITE_MANAGER_ROLE);
}
if (!hasLocalManagerPermission && authorityId) {
return authorityId;
}
return null;
}
updateReadOnlyPermission(node: Node, permissions: PermissionDisplayModel[]): PermissionDisplayModel[] {
permissions.forEach((permission) => {
if (!this.canUpdateThePermission(node, permission)) {
permission.readonly = true;
}
});
return permissions;
}
canUpdateThePermission(node: Node, permission: PermissionElement): boolean {
const sitePath = node.path.elements.find((path) => path.nodeType === 'st:site');
if (!node.permissions.isInheritanceEnabled && sitePath) {
const authorityId = `GROUP_site_${sitePath.name}_${this.SITE_MANAGER_ROLE}`;
return !(permission.authorityId === authorityId && permission.name === this.SITE_MANAGER_ROLE);
}
return true;
}
private isGroup(authorityId) {
return authorityId.startsWith('GROUP_') || authorityId.startsWith('ROLE_');
}

View File

@@ -24,6 +24,7 @@ export class PermissionDisplayModel implements PermissionElement {
accessStatus?: PermissionElement.AccessStatusEnum;
isInherited: boolean = false;
icon: string;
readonly?: boolean;
constructor(obj?: any) {
if (obj) {