mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-31 17:38:28 +00:00
[ACA-1273] Preview - node metadata (#272)
This commit is contained in:
committed by
Denys Vuika
parent
b63f6c0197
commit
142b179841
@@ -63,6 +63,7 @@ import { VersionManagerDialogAdapterComponent } from './components/versions-dial
|
||||
import { BrowsingFilesService } from './common/services/browsing-files.service';
|
||||
import { ContentManagementService } from './common/services/content-management.service';
|
||||
import { NodeActionsService } from './common/services/node-actions.service';
|
||||
import { NodePermissionService } from './common/services/node-permission.service';
|
||||
import { MatMenuModule, MatIconModule, MatButtonModule, MatDialogModule, MatInputModule } from '@angular/material';
|
||||
import { SearchComponent } from './components/search/search.component';
|
||||
|
||||
@@ -125,7 +126,8 @@ import { SearchComponent } from './components/search/search.component';
|
||||
},
|
||||
BrowsingFilesService,
|
||||
ContentManagementService,
|
||||
NodeActionsService
|
||||
NodeActionsService,
|
||||
NodePermissionService
|
||||
],
|
||||
entryComponents: [
|
||||
VersionManagerDialogAdapterComponent
|
||||
|
190
src/app/common/services/node-permission.service.spec.ts
Normal file
190
src/app/common/services/node-permission.service.spec.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NodePermissionService } from './node-permission.service';
|
||||
|
||||
describe('NodePermissionService', () => {
|
||||
let permission: NodePermissionService;
|
||||
|
||||
beforeEach(() => {
|
||||
permission = new NodePermissionService();
|
||||
});
|
||||
|
||||
|
||||
it('should return false when source is null', () => {
|
||||
const source = null;
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
describe('Multiple source permission', () => {
|
||||
it('should return true when source has allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['delete'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['delete'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'create'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has `AND` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'other'], 'AND')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'bogus'], 'AND')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: [] } },
|
||||
{ entry: { allowableOperations: [] } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations property', () => {
|
||||
const source = [
|
||||
{ entry: { } },
|
||||
{ entry: { } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Single source permission', () => {
|
||||
it('should return true when source has allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
||||
const source = { entry: { allowableOperationsOnTarget: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['delete'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||
const source = { entry: { allowableOperationsOnTarget: ['delete'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'create'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has `AND` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update', 'other'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'other'], 'AND')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'bogus'], 'AND')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations', () => {
|
||||
const source = { entry: { allowableOperations: [] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations property', () => {
|
||||
const source = { entry: { } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
77
src/app/common/services/node-permission.service.ts
Normal file
77
src/app/common/services/node-permission.service.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class NodePermissionService {
|
||||
static DEFAULT_OPERATION = 'OR';
|
||||
|
||||
check(source: any, permissions: string[], operation: string = NodePermissionService.DEFAULT_OPERATION): boolean {
|
||||
if (source) {
|
||||
if (Array.isArray(source) && source.length) {
|
||||
const arr = this.sanitize(source);
|
||||
|
||||
return !!arr.length && source.every(node => this.hasPermission(node, permissions, operation));
|
||||
}
|
||||
|
||||
return this.hasPermission(source, permissions, operation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private hasPermission(node, permissions, operation): boolean {
|
||||
const allowableOperations = this.getAllowableOperations(node);
|
||||
|
||||
if (allowableOperations.length) {
|
||||
if (operation === NodePermissionService.DEFAULT_OPERATION) {
|
||||
return permissions.some(permission => allowableOperations.includes(permission));
|
||||
} else {
|
||||
return permissions.every(permission => allowableOperations.includes(permission));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private getAllowableOperations(node): string[] {
|
||||
const entry = node.entry || node;
|
||||
|
||||
if (entry.allowableOperationsOnTarget) {
|
||||
return entry.allowableOperationsOnTarget;
|
||||
}
|
||||
|
||||
if (entry.allowableOperations) {
|
||||
return entry.allowableOperations;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private sanitize(selection): any[] {
|
||||
return (selection || []).filter(item => item);
|
||||
}
|
||||
}
|
@@ -1,7 +1,23 @@
|
||||
<ng-container *ngIf="nodeId">
|
||||
|
||||
<ng-template #sidebarTemplate>
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(node, ['update'])"
|
||||
[displayEmpty]="permission.check(node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</ng-template>
|
||||
|
||||
<adf-viewer
|
||||
[fileNodeId]="nodeId"
|
||||
[allowNavigate]="navigateMultiple"
|
||||
[allowSidebar]="true"
|
||||
[sidebarTemplate]="sidebarTemplate"
|
||||
[canNavigateBefore]="previousNodeId"
|
||||
[canNavigateNext]="nextNodeId"
|
||||
[overlayMode]="true"
|
||||
@@ -15,7 +31,10 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="selectedEntities">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -23,33 +42,32 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canCopyFile()"
|
||||
[app-copy-node]="selectedEntities">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canMoveFile()"
|
||||
*ngIf="permission.check(node, ['delete'])"
|
||||
[app-move-node]="selectedEntities">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canDeleteFile()"
|
||||
*ngIf="permission.check(node, ['delete'])"
|
||||
(click)="deleteFile()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canManageVersions()"
|
||||
*ngIf="permission.check(node, ['update'])"
|
||||
[app-node-versions]="selectedEntities">
|
||||
<mat-icon>storage</mat-icon>
|
||||
<mat-icon color="primary">storage</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</adf-viewer-more-actions>
|
||||
|
@@ -36,7 +36,7 @@ import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { PreviewComponent } from './preview.component';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { MatSnackBarModule } from '@angular/material';
|
||||
|
||||
describe('PreviewComponent', () => {
|
||||
@@ -64,7 +64,7 @@ describe('PreviewComponent', () => {
|
||||
CookieService,
|
||||
NotificationService,
|
||||
UserPreferencesService,
|
||||
ContentManagementService
|
||||
NodePermissionService
|
||||
],
|
||||
declarations: [
|
||||
PreviewComponent,
|
||||
|
@@ -27,7 +27,7 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AlfrescoApiService, UserPreferencesService, ObjectUtils } from '@alfresco/adf-core';
|
||||
import { Node, MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-preview',
|
||||
@@ -57,7 +57,7 @@ export class PreviewComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private apiService: AlfrescoApiService,
|
||||
private preferences: UserPreferencesService,
|
||||
private content: ContentManagementService) {
|
||||
public permission: NodePermissionService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -324,28 +324,11 @@ export class PreviewComponent implements OnInit {
|
||||
return path;
|
||||
}
|
||||
|
||||
canDeleteFile(): boolean {
|
||||
return this.content.canDeleteNode(this.node);
|
||||
}
|
||||
|
||||
async deleteFile() {
|
||||
try {
|
||||
await this.content.deleteNode(this.node);
|
||||
await this.permission.check(this.node, ['delete']);
|
||||
this.onVisibilityChanged(false);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
canMoveFile(): boolean {
|
||||
return this.content.canMoveNode(this.node);
|
||||
}
|
||||
|
||||
canCopyFile(): boolean {
|
||||
return this.content.canCopyNode(this.node);
|
||||
}
|
||||
|
||||
canManageVersions(): boolean {
|
||||
return this.node.isFile && this.content.nodeHasPermission(this.node, 'update');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -27,5 +27,6 @@ ng-component {
|
||||
@import './overrides/alfresco-upload-button';
|
||||
@import './overrides/alfresco-upload-dialog';
|
||||
@import './overrides/toolbar';
|
||||
@import './overrides/adf-viewer-more-actions';
|
||||
@import './overrides/breadcrumb';
|
||||
@import './overrides/adf-info-drawer';
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
@import '../components/sidenav/sidenav.component.theme';
|
||||
@import './overrides/toolbar';
|
||||
@import './overrides/adf-viewer-more-actions';
|
||||
|
||||
$grey-scale: (
|
||||
50 : #e0e0e0,
|
||||
@@ -47,4 +48,5 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent);
|
||||
@mixin custom-theme($theme) {
|
||||
@include sidenav-component-theme($custom-theme);
|
||||
@include toolbar-component-theme($custom-theme);
|
||||
@include viewer-more-actions-component-theme($custom-theme);
|
||||
}
|
||||
|
18
src/app/ui/overrides/_adf-viewer-more-actions.scss
Normal file
18
src/app/ui/overrides/_adf-viewer-more-actions.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
@mixin viewer-more-actions-component-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
.adf-viewer-more-actions {
|
||||
@include angular-material-theme($theme);
|
||||
|
||||
.toolbar__option--active {
|
||||
color: mat-color($accent) !important;
|
||||
}
|
||||
|
||||
.toolbar__option--default {
|
||||
color: mat-color($primary, .87) !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user