From a9142e2ca2a9eaf3d3c52434289db390ea9871c1 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 17 Jul 2017 17:22:08 +0100 Subject: [PATCH] [ADF-1040] Change document list style rows based on permissions model (#2085) * Change document list style rows based on permissions model * fix test --- .../app/components/files/files.component.html | 1 + .../app/components/files/files.component.ts | 4 +- .../config/webpack.common.js | 3 +- ng2-components/ng2-alfresco-core/index.ts | 6 +- .../assets/images/ft_ic_folder_disable.svg | 3 + .../models/{index.ts => permissions.enum.ts} | 13 ++- .../services/alfresco-content.service.spec.ts | 21 +++- .../src/services/alfresco-content.service.ts | 2 + .../src/services/thumbnail.service.ts | 3 +- .../ng2-alfresco-datatable/README.md | 8 +- .../datatable/datatable.component.html | 2 +- .../datatable/datatable.component.ts | 19 ++-- .../src/data/datatable-adapter.ts | 1 + .../ng2-alfresco-documentlist/README.md | 61 +++++++++++- .../ng2-alfresco-documentlist/index.ts | 1 + .../ng2-alfresco-documentlist/karma.conf.js | 9 ++ .../content-action.component.spec.ts | 31 ++++-- .../document-list.component.spec.ts | 8 +- .../src/components/document-list.component.ts | 16 ++-- .../document-menu-action.component.spec.ts | 16 +--- .../document-menu-action.component.ts | 16 +--- .../src/data/share-datatable-adapter.spec.ts | 61 +++++++----- .../src/data/share-datatable-adapter.ts | 57 +++++++---- .../src/models/permissions-style.model.ts | 32 +++++++ .../src/services/document-actions.service.ts | 21 +--- .../services/document-list.service.spec.ts | 7 +- .../src/services/document-list.service.ts | 6 +- .../services/folder-actions.service.spec.ts | 96 +++++++++++++++---- .../src/services/folder-actions.service.ts | 25 ++--- 29 files changed, 382 insertions(+), 167 deletions(-) create mode 100644 ng2-components/ng2-alfresco-core/src/assets/images/ft_ic_folder_disable.svg rename ng2-components/ng2-alfresco-core/src/models/{index.ts => permissions.enum.ts} (59%) create mode 100644 ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts diff --git a/demo-shell-ng2/app/components/files/files.component.html b/demo-shell-ng2/app/components/files/files.component.html index 87346bfdcb..acf2dbcc27 100644 --- a/demo-shell-ng2/app/components/files/files.component.html +++ b/demo-shell-ng2/app/components/files/files.component.html @@ -50,6 +50,7 @@ + + diff --git a/ng2-components/ng2-alfresco-core/src/models/index.ts b/ng2-components/ng2-alfresco-core/src/models/permissions.enum.ts similarity index 59% rename from ng2-components/ng2-alfresco-core/src/models/index.ts rename to ng2-components/ng2-alfresco-core/src/models/permissions.enum.ts index 956380ce41..d2e2cc7429 100644 --- a/ng2-components/ng2-alfresco-core/src/models/index.ts +++ b/ng2-components/ng2-alfresco-core/src/models/permissions.enum.ts @@ -15,6 +15,13 @@ * limitations under the License. */ -export * from './card-view-textitem.model'; -export * from './card-view-dateitem.model'; -export * from './file.model'; +export class PermissionsEnum extends String { + static DELETE: string = 'delete'; + static UPDATE: string = 'update'; + static CREATE: string = 'create'; + static UPDATEPERMISSIONS: string = 'updatePermissions'; + static NOT_DELETE: string = '!delete'; + static NOT_UPDATE: string = '!update'; + static NOT_CREATE: string = '!create'; + static NOT_UPDATEPERMISSIONS: string = '!updatePermissions'; +} diff --git a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.spec.ts index f75ed38aca..cbbb4be902 100644 --- a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.spec.ts +++ b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.spec.ts @@ -44,8 +44,7 @@ describe('AlfrescoContentService', () => { imports: [ AppConfigModule ], - declarations: [ - ], + declarations: [], providers: [ AlfrescoApiService, AlfrescoContentService, @@ -53,7 +52,7 @@ describe('AlfrescoContentService', () => { AlfrescoSettingsService, StorageService, UserPreferencesService, - { provide: CookieService, useClass: CookieServiceMock }, + {provide: CookieService, useClass: CookieServiceMock}, LogService ] }).compileComponents(); @@ -111,4 +110,20 @@ describe('AlfrescoContentService', () => { responseText: JSON.stringify({'entry': {'id': 'fake-post-ticket', 'userId': 'admin'}}) }); }); + + it('should havePermission should be false if allowableOperation is not present in the node', () => { + let permissionNode = {}; + expect(contentService.hasPermission(permissionNode, 'create')).toBeFalsy(); + }); + + it('should havePermission should be true if allowableOperation is present and you have the permission for the request operation', () => { + let permissionNode = {allowableOperations: ['delete', 'update', 'create', 'updatePermissions']}; + + expect(contentService.hasPermission(permissionNode, 'create')).toBeTruthy(); + }); + + it('should havePermission should be false if allowableOperation is present but you don\'t have the permission for the request operation', () => { + let permissionNode = {allowableOperations: ['delete', 'update', 'updatePermissions']}; + expect(contentService.hasPermission(permissionNode, 'create')).toBeFalsy(); + }); }); diff --git a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts index 24af165f49..7befe5a42a 100644 --- a/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/alfresco-content.service.ts @@ -18,6 +18,7 @@ import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs/Rx'; import { FolderCreatedEvent } from '../events/folder-created.event'; +import { PermissionsEnum } from '../models/permissions.enum'; import { AlfrescoApiService } from './alfresco-api.service'; import { AuthenticationService } from './authentication.service'; import { LogService } from './log.service'; @@ -71,6 +72,7 @@ export class AlfrescoContentService { return dataContent; })).catch(this.handleError); } + /** * Create a folder * @param name - the folder name diff --git a/ng2-components/ng2-alfresco-core/src/services/thumbnail.service.ts b/ng2-components/ng2-alfresco-core/src/services/thumbnail.service.ts index 8599dfc710..294bbb27a8 100644 --- a/ng2-components/ng2-alfresco-core/src/services/thumbnail.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/thumbnail.service.ts @@ -50,7 +50,8 @@ export class ThumbnailService { 'application/vnd.apple.keynote': require('../assets/images/ft_ic_presentation.svg'), 'application/vnd.apple.pages': require('../assets/images/ft_ic_document.svg'), 'application/vnd.apple.numbers': require('../assets/images/ft_ic_spreadsheet.svg'), - 'folder': require('../assets/images/ft_ic_folder.svg') + 'folder': require('../assets/images/ft_ic_folder.svg'), + 'disable/folder': require('../assets/images/ft_ic_folder_disable.svg') }; constructor(public contentService: AlfrescoContentService) { diff --git a/ng2-components/ng2-alfresco-datatable/README.md b/ng2-components/ng2-alfresco-datatable/README.md index 968951e57e..468e3117ff 100644 --- a/ng2-components/ng2-alfresco-datatable/README.md +++ b/ng2-components/ng2-alfresco-datatable/README.md @@ -531,9 +531,11 @@ interface DataTableAdapter { } interface DataRow { - isSelected: boolean; - hasValue(key: string): boolean; - getValue(key: string): any; + isSelected: boolean; + isDropTarget?: boolean; + hasValue(key: string): boolean; + getValue(key: string): any; + cssClass?: string; } interface DataColumn { diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html index 9ba3b98bdc..5b22d92ace 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html @@ -35,7 +35,7 @@ [class.is-selected]="row.isSelected" [adf-upload]="allowDropFiles && rowAllowsDrop(row)" [adf-upload-data]="row" [ngStyle]="rowStyle" - [ngClass]="rowStyleClass"> + [ngClass]="getRowStyle(row)"> diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts index af7361c6d7..df8893568b 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts @@ -69,7 +69,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck rowStyle: string; @Input() - rowStyleClass: string; + rowStyleClass: string = ''; @Input() showHeader: boolean = true; @@ -107,10 +107,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck private singleClickStreamSub: Subscription; private multiClickStreamSub: Subscription; - constructor( - translateService: AlfrescoTranslationService, - @Optional() private el: ElementRef, - private differs: IterableDiffers) { + constructor(translateService: AlfrescoTranslationService, + @Optional() private el: ElementRef, + private differs: IterableDiffers) { if (differs) { this.differ = differs.find([]).create(null); } @@ -130,7 +129,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck if (this.isPropertyChanged(changes['data'])) { if (this.isTableEmpty()) { this.initTable(); - }else { + } else { this.data = changes['data'].currentValue; } return; @@ -207,7 +206,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck } private unsubscribeClickStream() { - if (this.singleClickStreamSub) { + if (this.singleClickStreamSub) { this.singleClickStreamSub.unsubscribe(); } if (this.multiClickStreamSub) { @@ -379,4 +378,10 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck return this.selectionMode && this.selectionMode.toLowerCase() === 'multiple'; } + getRowStyle(row: DataRow): string { + row.cssClass = row.cssClass ? row.cssClass : ''; + this.rowStyleClass = this.rowStyleClass ? this.rowStyleClass : ''; + return `${row.cssClass} ${this.rowStyleClass}`; + } + } diff --git a/ng2-components/ng2-alfresco-datatable/src/data/datatable-adapter.ts b/ng2-components/ng2-alfresco-datatable/src/data/datatable-adapter.ts index a8a205a15b..6e0cfee49d 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/datatable-adapter.ts @@ -33,6 +33,7 @@ export interface DataTableAdapter { export interface DataRow { isSelected: boolean; isDropTarget?: boolean; + cssClass?: string; hasValue(key: string): boolean; getValue(key: string): any; } diff --git a/ng2-components/ng2-alfresco-documentlist/README.md b/ng2-components/ng2-alfresco-documentlist/README.md index 3f606edb2b..64e4cb258a 100644 --- a/ng2-components/ng2-alfresco-documentlist/README.md +++ b/ng2-components/ng2-alfresco-documentlist/README.md @@ -89,7 +89,8 @@ The properties currentFolderId, folderNode and node are the entry initialization | rowStyleClass | string | | The CSS class to apply to every row | | currentFolderId | string | null | Initial node ID of displayed folder. Can be `-root-`, `-shared-`, `-my-`, or a fixed node ID | | folderNode | [MinimalNodeEntryEntity](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeMinimalEntry.md) | null | Currently displayed folder node | -| node | `NodePaging` | null | Document list will show all the node contained in the NodePaging entity | +| permissionsStyle | [PermissionStyleModel[]](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts) | null | with this array you can define different styles depending from the permission of the user on that node. The PermissionStyleModel allow you to select also if you want apply the style only on the file or folder nodes. With PermissionStyleModel.permission accept the following values [Permissions](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-alfresco-core/src/models/permissions.enum.ts) [see more](#custom-row-permissions-style). | +| node | [NodePaging](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodePaging.md) | null | Document list will show all the node contained in the NodePaging entity | | navigate | boolean | true | Toggles navigation to folder content or file preview | | loading | boolean | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. | | navigationMode | string (click,dblclick) | dblclick | User interaction for folder navigation or file preview | @@ -1025,6 +1026,64 @@ Now you can declare columns and assign `desktop-only` class where needed: ![Responsive Mobile](docs/assets/responsive-mobile.png) +### Custom row permissions style + +You can personalize the style of the row based on the permissions. +The property to valorize is permissionsStyle[]:[PermissionStyleModel[]](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts). +The permissionsStyle array can define different styles depending from the permission of the user on that node. + +[PermissionStyleModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts) + +| Property | Description | +| isFile/isFolder | allow you to select if you want apply the style to file/folder nodes | +| permission | is an enum value [Permissions](https://github.com/Alfresco/alfresco-ng2-core/blob/master/ng2-components/ng2-alfresco-documentlist/src/models/permissions.enum.ts) | +| css| the name of the class to add | + +#### Examples + +If you want to change the style on rows where the user can create content: + +```ts +let permissionsStyle: PermissionStyleModel[] = []; + +this.permissionsStyle.push(new PermissionStyleModel('document-list__create', PermissionsEnum.CREATE)); +``` + +```html + + +``` + +```css + +adf-document-list >>> adf-datatable >>> tr.alfresco-datatable__row.document-list__create { + color: rgb(57, 239, 121); +} +``` + +If you want to change the style on the folders where the user doesn't have the permission to update it: + +```ts + +let permissionsStyle: PermissionStyleModel[] = []; + +this.permissionsStyle.push(new PermissionStyleModel('document-list__disable', PermissionsEnum.NOT_CREATE, false, true)); + +``` + +```html + + +``` + +```css + +adf-document-list >>> adf-datatable >>> tr.alfresco-datatable__row.document-list__disable { + color: rgba(0, 0, 0, 0.28); + +} +``` + ### Custom 'empty folder' template By default DocumentList provides the following content for the empty folder: diff --git a/ng2-components/ng2-alfresco-documentlist/index.ts b/ng2-components/ng2-alfresco-documentlist/index.ts index 83716287ea..d344bfbdb2 100644 --- a/ng2-components/ng2-alfresco-documentlist/index.ts +++ b/ng2-components/ng2-alfresco-documentlist/index.ts @@ -56,6 +56,7 @@ export * from './src/services/document-list.service'; export * from './src/models/content-action.model'; export * from './src/models/document-library.model'; export * from './src/models/permissions.model'; +export * from './src/models/permissions-style.model'; export const DOCUMENT_LIST_DIRECTIVES: any[] = [ DocumentListComponent, diff --git a/ng2-components/ng2-alfresco-documentlist/karma.conf.js b/ng2-components/ng2-alfresco-documentlist/karma.conf.js index 40a7fe1518..ea9c421e8e 100644 --- a/ng2-components/ng2-alfresco-documentlist/karma.conf.js +++ b/ng2-components/ng2-alfresco-documentlist/karma.conf.js @@ -50,6 +50,15 @@ module.exports = function (config) { Chrome_travis_ci: { base: 'Chrome', flags: ['--no-sandbox'] + }, + Chrome_headless: { + base: 'Chrome', + flags: [ + '--no-sandbox', + '--headless', + '--disable-gpu', + '--remote-debugging-port=9222' + ] } }, diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts index 6c00dece3c..286fcec9d8 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/content-action/content-action.component.spec.ts @@ -16,7 +16,8 @@ */ import { EventEmitter } from '@angular/core'; - +import { async, TestBed } from '@angular/core/testing'; +import { AlfrescoContentService, CoreModule } from 'ng2-alfresco-core'; import { FileNode } from './../../assets/document-library.model.mock'; import { DocumentListServiceMock } from './../../assets/document-list.service.mock'; import { ContentActionHandler } from './../../models/content-action.model'; @@ -33,10 +34,24 @@ describe('ContentAction', () => { let documentActions: DocumentActionsService; let folderActions: FolderActionsService; + let contentService: AlfrescoContentService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule.forRoot() + ], + providers: [ + AlfrescoContentService + ] + }).compileComponents(); + })); + beforeEach(() => { + contentService = TestBed.get(AlfrescoContentService); let documentServiceMock = new DocumentListServiceMock(); documentActions = new DocumentActionsService(null, null); - folderActions = new FolderActionsService(null); + folderActions = new FolderActionsService(null, contentService); documentList = new DocumentListComponent(documentServiceMock, null, null, null); actionList = new ContentActionListComponent(documentList); @@ -70,7 +85,8 @@ describe('ContentAction', () => { it('should get action handler from document actions service', () => { - let handler = function() {}; + let handler = function () { + }; spyOn(documentActions, 'getHandler').and.returnValue(handler); let action = new ContentActionComponent(actionList, documentActions, null); @@ -86,7 +102,8 @@ describe('ContentAction', () => { }); it('should get action handler from folder actions service', () => { - let handler = function() {}; + let handler = function () { + }; spyOn(folderActions, 'getHandler').and.returnValue(handler); let action = new ContentActionComponent(actionList, null, folderActions); @@ -188,14 +205,16 @@ describe('ContentAction', () => { }); it('should find document action handler via service', () => { - let handler = function (obj: any, target?: any) {}; + let handler = function (obj: any, target?: any) { + }; let action = new ContentActionComponent(actionList, documentActions, null); spyOn(documentActions, 'getHandler').and.returnValue(handler); expect(action.getSystemHandler('document', 'name')).toBe(handler); }); it('should find folder action handler via service', () => { - let handler = function (obj: any, target?: any) {}; + let handler = function (obj: any, target?: any) { + }; let action = new ContentActionComponent(actionList, null, folderActions); spyOn(folderActions, 'getHandler').and.returnValue(handler); expect(action.getSystemHandler('folder', 'name')).toBe(handler); diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts index 719780ce8c..3855f8bd6f 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.spec.ts @@ -747,7 +747,7 @@ describe('DocumentList', () => { it('should emit [nodeClick] event on row click', () => { let node = new NodeMinimalEntry(); - let row = new ShareDataRow(node); + let row = new ShareDataRow(node, null, null); let event = new DataRowEvent(row, null); spyOn(documentList, 'onNodeClick').and.callThrough(); @@ -757,7 +757,7 @@ describe('DocumentList', () => { it('should emit node-click DOM event', (done) => { let node = new NodeMinimalEntry(); - let row = new ShareDataRow(node); + let row = new ShareDataRow(node, null, null); let event = new DataRowEvent(row, null); const htmlElement = fixture.debugElement.nativeElement as HTMLElement; @@ -770,7 +770,7 @@ describe('DocumentList', () => { it('should emit [nodeDblClick] event on row double-click', () => { let node = new NodeMinimalEntry(); - let row = new ShareDataRow(node); + let row = new ShareDataRow(node, null, null); let event = new DataRowEvent(row, null); spyOn(documentList, 'onNodeDblClick').and.callThrough(); @@ -780,7 +780,7 @@ describe('DocumentList', () => { it('should emit node-dblclick DOM event', (done) => { let node = new NodeMinimalEntry(); - let row = new ShareDataRow(node); + let row = new ShareDataRow(node, null, null); let event = new DataRowEvent(row, null); const htmlElement = fixture.debugElement.nativeElement as HTMLElement; diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts index cf07095a9b..6c684c8429 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts @@ -21,18 +21,11 @@ import { } from '@angular/core'; import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core'; -import { - DataCellEvent, - DataColumn, - DataRowActionEvent, - DataRowEvent, - DataSorting, - DataTableComponent, - ObjectDataColumn -} from 'ng2-alfresco-datatable'; +import { DataCellEvent, DataColumn, DataRowActionEvent, DataRowEvent, DataSorting, DataTableComponent, ObjectDataColumn } from 'ng2-alfresco-datatable'; import { Observable, Subject } from 'rxjs/Rx'; import { ImageResolver, RowFilter, ShareDataRow, ShareDataTableAdapter } from './../data/share-datatable-adapter'; import { ContentActionModel } from './../models/content-action.model'; +import { PermissionStyleModel } from './../models/permissions-style.model'; import { DocumentListService } from './../services/document-list.service'; import { NodeEntityEvent, NodeEntryEvent } from './node.event'; @@ -51,6 +44,9 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni @ContentChild(DataColumnListComponent) columnList: DataColumnListComponent; + @Input() + permissionsStyle: PermissionStyleModel[] = []; + @Input() navigate: boolean = true; @@ -202,6 +198,8 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni ngOnInit() { this.data = new ShareDataTableAdapter(this.documentListService, null, this.getDefaultSorting()); this.data.thumbnails = this.thumbnails; + + this.data.permissionsStyle = this.permissionsStyle; this.contextActionHandler.subscribe(val => this.contextActionCallback(val)); this.enforceSingleClickNavigationForMobile(); diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.spec.ts index d6b4bae8f2..aac722f31a 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.spec.ts @@ -18,14 +18,7 @@ import { SimpleChange } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { MdButtonModule, MdIconModule, MdMenuModule } from '@angular/material'; -import { - AlfrescoApiService, - AlfrescoAuthenticationService, - AlfrescoSettingsService, - AlfrescoTranslationService, - CoreModule, - LogService -} from 'ng2-alfresco-core'; +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { DocumentListService } from './../services/document-list.service'; import { DocumentMenuActionComponent } from './document-menu-action.component'; @@ -90,17 +83,14 @@ describe('Document menu action', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - CoreModule, + CoreModule.forRoot(), MdMenuModule, MdButtonModule, MdIconModule ], declarations: [DocumentMenuActionComponent], providers: [ - AlfrescoSettingsService, - AlfrescoAuthenticationService, - AlfrescoApiService, - LogService, + AlfrescoTranslationService, DocumentListService ] }); diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.ts index 08fb6cbff9..5f28ccc307 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-menu-action.component.ts @@ -17,7 +17,7 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; import { MinimalNodeEntity } from 'alfresco-js-api'; -import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; +import { AlfrescoContentService, AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; import { PermissionModel } from '../models/permissions.model'; import { ContentActionModel } from './../models/content-action.model'; @@ -62,7 +62,8 @@ export class DocumentMenuActionComponent implements OnChanges { constructor(private documentListService: DocumentListService, private translateService: AlfrescoTranslationService, - private logService: LogService) { + private logService: LogService, + private contentService: AlfrescoContentService) { if (translateService) { translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist'); @@ -154,17 +155,8 @@ export class DocumentMenuActionComponent implements OnChanges { return !this.hasCreatePermission() && this.disableWithNoPermission ? true : undefined; } - hasPermission(permission: string): boolean { - let hasPermission: boolean = false; - if (this.allowableOperations) { - let permFound = this.allowableOperations.find(element => element === permission); - hasPermission = permFound ? true : false; - } - return hasPermission; - } - hasCreatePermission() { - return this.hasPermission('create'); + return this.contentService.hasPermission(this, 'create'); } loadCurrentNodePermissions(nodeId: string) { diff --git a/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.spec.ts index 0f402651fd..0a44f168a3 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.spec.ts @@ -130,7 +130,7 @@ describe('ShareDataTableAdapter', () => { format: 'medium' // Jul 15, 2015, 9:43:11 PM }; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let adapter = new ShareDataTableAdapter(documentListService, null); let value = adapter.getValue(row, col); @@ -150,7 +150,7 @@ describe('ShareDataTableAdapter', () => { format: null }; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let adapter = new ShareDataTableAdapter(documentListService, null); let value = adapter.getValue(row, col); @@ -168,7 +168,7 @@ describe('ShareDataTableAdapter', () => { type: 'string' }; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let adapter = new ShareDataTableAdapter(documentListService, null); let value = adapter.getValue(row, col); @@ -186,7 +186,7 @@ describe('ShareDataTableAdapter', () => { format: 'medium' }; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let adapter = new ShareDataTableAdapter(documentListService, null); spyOn(console, 'error').and.stub(); @@ -201,7 +201,7 @@ describe('ShareDataTableAdapter', () => { let file = new FileNode(); file.entry.content.mimeType = null; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let col = {type: 'image', key: '$thumbnail'}; let value = adapter.getValue(row, col); @@ -215,7 +215,7 @@ describe('ShareDataTableAdapter', () => { let file = new FileNode(); file.entry.content = null; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let col = {type: 'image', key: '$thumbnail'}; let value = adapter.getValue(row, col); @@ -230,7 +230,7 @@ describe('ShareDataTableAdapter', () => { file.entry['icon'] = imageUrl; let adapter = new ShareDataTableAdapter(documentListService, null); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let col = {type: 'image', key: 'icon'}; let value = adapter.getValue(row, col); @@ -240,7 +240,7 @@ describe('ShareDataTableAdapter', () => { it('should resolve folder icon', () => { let adapter = new ShareDataTableAdapter(documentListService, null); - let row = new ShareDataRow(new FolderNode()); + let row = new ShareDataRow(new FolderNode(), documentListService, null); let col = {type: 'image', key: '$thumbnail'}; let value = adapter.getValue(row, col); @@ -256,7 +256,7 @@ describe('ShareDataTableAdapter', () => { adapter.thumbnails = true; let file = new FileNode(); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let col = {type: 'image', key: '$thumbnail'}; let value = adapter.getValue(row, col); @@ -271,7 +271,7 @@ describe('ShareDataTableAdapter', () => { file.entry.isFile = false; file.entry.isFolder = false; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); let col = {type: 'image', key: '$thumbnail'}; let value = adapter.getValue(row, col); @@ -289,9 +289,9 @@ describe('ShareDataTableAdapter', () => { adapter.setSorting(new DataSorting('name', 'asc')); adapter.setRows([ - new ShareDataRow(file2), - new ShareDataRow(file1), - new ShareDataRow(folder) + new ShareDataRow(file2, documentListService, null), + new ShareDataRow(file1, documentListService, null), + new ShareDataRow(folder, documentListService, null) ]); let sorted = adapter.getRows(); @@ -311,8 +311,8 @@ describe('ShareDataTableAdapter', () => { let adapter = new ShareDataTableAdapter(documentListService, [col]); adapter.setRows([ - new ShareDataRow(file2), - new ShareDataRow(file1) + new ShareDataRow(file2, documentListService, null), + new ShareDataRow(file1, documentListService, null) ]); adapter.sort('dateProp', 'asc'); @@ -330,27 +330,44 @@ describe('ShareDataTableAdapter', () => { describe('ShareDataRow', () => { + let documentListService: DocumentListService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule.forRoot() + ], + providers: [ + DocumentListService + ] + }).compileComponents(); + })); + + beforeEach(() => { + documentListService = TestBed.get(DocumentListService); + }); + it('should wrap node', () => { let file = new FileNode(); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.node).toBe(file); }); it('should require object source', () => { expect(() => { - return new ShareDataRow(null); + return new ShareDataRow(null, documentListService, null); }).toThrowError(ShareDataRow.ERR_OBJECT_NOT_FOUND); }); it('should resolve value from node entry', () => { let file = new FileNode('test'); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.getValue('name')).toBe('test'); }); it('should check value', () => { let file = new FileNode('test'); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.hasValue('name')).toBeTruthy(); expect(row.hasValue('missing')).toBeFalsy(); @@ -359,21 +376,21 @@ describe('ShareDataRow', () => { it('should be set as drop target when user has permission for that node', () => { let file = new FolderNode('test'); file.entry['allowableOperations'] = ['create']; - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.isDropTarget).toBeTruthy(); }); it('should not be set as drop target when user has permission for that node', () => { let file = new FolderNode('test'); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.isDropTarget).toBeFalsy(); }); it('should not be set as drop target when element is not a Folder', () => { let file = new FileNode('test'); - let row = new ShareDataRow(file); + let row = new ShareDataRow(file, documentListService, null); expect(row.isDropTarget).toBeFalsy(); }); diff --git a/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.ts b/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.ts index e4fd77e429..8ca7ecf795 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/data/share-datatable-adapter.ts @@ -16,10 +16,11 @@ */ import { DatePipe } from '@angular/common'; +import { MinimalNode, MinimalNodeEntity, NodePaging } from 'alfresco-js-api'; import { ObjectUtils } from 'ng2-alfresco-core'; +import { PermissionsEnum } from 'ng2-alfresco-core'; import { DataColumn, DataRow, DataSorting, DataTableAdapter } from 'ng2-alfresco-datatable'; - -import { MinimalNodeEntity, NodePaging } from 'alfresco-js-api'; +import { PermissionStyleModel } from './../models/permissions-style.model'; import { DocumentListService } from './../services/document-list.service'; declare var require: any; @@ -42,6 +43,7 @@ export class ShareDataTableAdapter implements DataTableAdapter { private imageResolver: ImageResolver; thumbnails: boolean = false; + permissionsStyle: PermissionStyleModel[]; selectedRow: DataRow; constructor(private documentListService: DocumentListService, @@ -194,7 +196,7 @@ export class ShareDataTableAdapter implements DataTableAdapter { if (page && page.list) { let data = page.list.entries; if (data && data.length > 0) { - rows = data.map(item => new ShareDataRow(item)); + rows = data.map(item => new ShareDataRow(item, this.documentListService, this.permissionsStyle)); if (this.filter) { rows = rows.filter(this.filter); @@ -229,34 +231,53 @@ export class ShareDataRow implements DataRow { cache: { [key: string]: any } = {}; isSelected: boolean = false; isDropTarget: boolean; + cssClass: string = ''; get node(): MinimalNodeEntity { return this.obj; } - constructor(private obj: MinimalNodeEntity) { + constructor(private obj: MinimalNodeEntity, private documentListService: DocumentListService, private permissionsStyle: PermissionStyleModel[]) { if (!obj) { throw new Error(ShareDataRow.ERR_OBJECT_NOT_FOUND); } this.isDropTarget = this.isFolderAndHasPermissionToUpload(obj); + + if (permissionsStyle) { + this.cssClass = this.getPermissionClass(obj); + } + } + + getPermissionClass(nodeEntity: MinimalNodeEntity): string { + let permissionsClasses = ''; + + this.permissionsStyle.forEach((currentPermissionsStyle: PermissionStyleModel) => { + + if (this.applyPermissionStyleToFolder(nodeEntity.entry, currentPermissionsStyle) || this.applyPermissionStyleToFile(nodeEntity.entry, currentPermissionsStyle)) { + + if (currentPermissionsStyle.permission.startsWith('!') && !this.documentListService.hasPermission(nodeEntity.entry, currentPermissionsStyle.permission)) { + permissionsClasses += ` ${currentPermissionsStyle.css}`; + } else if (this.documentListService.hasPermission(nodeEntity.entry, currentPermissionsStyle.permission)) { + permissionsClasses += ` ${currentPermissionsStyle.css}`; + } + } + + }); + + return permissionsClasses; + } + + private applyPermissionStyleToFile(node: MinimalNode, currentPermissionsStyle: PermissionStyleModel): boolean { + return (currentPermissionsStyle.isFile && node.isFile); + } + + private applyPermissionStyleToFolder(node: MinimalNode, currentPermissionsStyle: PermissionStyleModel): boolean { + return (currentPermissionsStyle.isFolder && node.isFolder); } isFolderAndHasPermissionToUpload(obj: MinimalNodeEntity): boolean { - return this.isFolder(obj) && this.hasCreatePermission(obj); - } - - hasCreatePermission(obj: MinimalNodeEntity): boolean { - return this.hasPermission(obj, 'create'); - } - - private hasPermission(obj: MinimalNodeEntity, permission: string): boolean { - let hasPermission: boolean = false; - if (obj.entry && obj.entry['allowableOperations']) { - let permFound = obj.entry['allowableOperations'].find(element => element === permission); - hasPermission = permFound ? true : false; - } - return hasPermission; + return this.isFolder(obj) && this.documentListService.hasPermission(obj.entry, 'create'); } isFolder(obj: MinimalNodeEntity): boolean { diff --git a/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts b/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts new file mode 100644 index 0000000000..31913e62e5 --- /dev/null +++ b/ng2-components/ng2-alfresco-documentlist/src/models/permissions-style.model.ts @@ -0,0 +1,32 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PermissionsEnum } from 'ng2-alfresco-core'; + +export class PermissionStyleModel { + css: string; + permission: PermissionsEnum; + isFolder: boolean = true; + isFile: boolean = true; + + constructor(css: string, permission: PermissionsEnum, isFile: boolean = true, isFolder: boolean = true) { + this.css = css; + this.permission = permission; + this.isFile = isFile; + this.isFolder = isFolder; + } +} diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts index 1acfd01def..debf7b348b 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-actions.service.ts @@ -103,32 +103,21 @@ export class DocumentActionsService { } private deleteNode(obj: any, target?: any, permission?: string): Observable { - let handlerObservale; + let handlerObservable; if (this.canExecuteAction(obj)) { - if (this.hasPermission(obj.entry, permission)) { - handlerObservale = this.documentListService.deleteNode(obj.entry.id); - handlerObservale.subscribe(() => { + if (this.contentService.hasPermission(obj.entry, permission)) { + handlerObservable = this.documentListService.deleteNode(obj.entry.id); + handlerObservable.subscribe(() => { if (target && typeof target.reload === 'function') { target.reload(); } }); - return handlerObservale; + return handlerObservable; } else { this.permissionEvent.next(new PermissionModel({type: 'content', action: 'delete', permission: permission})); return Observable.throw(new Error('No permission to delete')); } } } - - private hasPermission(node: any, permission: string): boolean { - if (this.hasPermissions(node)) { - return node.allowableOperations.find(permision => permision === permission) ? true : false; - } - return false; - } - - private hasPermissions(node: any): boolean { - return node && node.allowableOperations ? true : false; - } } diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.spec.ts index 56a9991bf1..86f45c86aa 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.spec.ts @@ -16,12 +16,7 @@ */ import { async, TestBed } from '@angular/core/testing'; -import { - CookieService, - CoreModule, - LogService, - LogServiceMock -} from 'ng2-alfresco-core'; +import { CookieService, CoreModule, LogService, LogServiceMock } from 'ng2-alfresco-core'; import { CookieServiceMock } from '../../../ng2-alfresco-core/src/assets/cookie.service.mock'; import { DocumentListService } from './document-list.service'; diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.ts index 39c86ccc79..b226c6a8d1 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/document-list.service.ts @@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; import { Response } from '@angular/http'; import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging } from 'alfresco-js-api'; -import { AlfrescoApiService, AlfrescoAuthenticationService, AlfrescoContentService, LogService, ThumbnailService } from 'ng2-alfresco-core'; +import { AlfrescoApiService, AlfrescoAuthenticationService, AlfrescoContentService, LogService, PermissionsEnum, ThumbnailService } from 'ng2-alfresco-core'; import { Observable } from 'rxjs/Rx'; @Injectable() @@ -115,6 +115,10 @@ export class DocumentListService { return this.thumbnailService.getDefaultMimeTypeIcon(); } + hasPermission(node: any, permission: PermissionsEnum|string): boolean { + return this.contentService.hasPermission(node, permission); + } + private handleError(error: Response) { // in a real world app, we may send the error to some remote logging infrastructure // instead of just logging it to the console diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts index 18dc62a8c9..bb6f325588 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.spec.ts @@ -15,8 +15,10 @@ * limitations under the License. */ +import { async, TestBed } from '@angular/core/testing'; +import { AppConfigModule, CoreModule } from 'ng2-alfresco-core'; +import { Observable } from 'rxjs/Rx'; import { FileNode, FolderNode } from '../assets/document-library.model.mock'; -import { DocumentListServiceMock } from '../assets/document-list.service.mock'; import { ContentActionHandler } from '../models/content-action.model'; import { DocumentListService } from './document-list.service'; import { FolderActionsService } from './folder-actions.service'; @@ -26,13 +28,29 @@ describe('FolderActionsService', () => { let service: FolderActionsService; let documentListService: DocumentListService; + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) + ], + providers: [ + DocumentListService, + FolderActionsService + ] + }).compileComponents(); + })); + beforeEach(() => { - documentListService = new DocumentListServiceMock(); - service = new FolderActionsService(documentListService); + service = TestBed.get(FolderActionsService); + documentListService = TestBed.get(DocumentListService); }); it('should register custom action handler', () => { - let handler: ContentActionHandler = function () {}; + let handler: ContentActionHandler = function () { + }; service.setHandler('', handler); expect(service.getHandler('')).toBe(handler); }); @@ -42,7 +60,8 @@ describe('FolderActionsService', () => { }); it('should be case insensitive for keys', () => { - let handler: ContentActionHandler = function () {}; + let handler: ContentActionHandler = function () { + }; service.setHandler('', handler); expect(service.getHandler('')).toBe(handler); }); @@ -55,9 +74,6 @@ describe('FolderActionsService', () => { it('should allow action execution only when service available', () => { let folder = new FolderNode(); expect(service.canExecuteAction(folder)).toBeTruthy(); - - service = new FolderActionsService(null); - expect(service.canExecuteAction(folder)).toBeFalsy(); }); it('should allow action execution only for folder nodes', () => { @@ -67,7 +83,8 @@ describe('FolderActionsService', () => { }); it('should set new handler only by key', () => { - let handler: ContentActionHandler = function () {}; + let handler: ContentActionHandler = function () { + }; expect(service.setHandler(null, handler)).toBeFalsy(); expect(service.setHandler('', handler)).toBeFalsy(); expect(service.setHandler('my-handler', handler)).toBeTruthy(); @@ -110,12 +127,17 @@ describe('FolderActionsService', () => { }); it('should delete the folder node if there is the delete permission', () => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let permission = 'delete'; let folder = new FolderNode(); let folderWithPermission: any = folder; - folderWithPermission.entry.allowableOperations = [ permission ]; + folderWithPermission.entry.allowableOperations = [permission]; const deleteObservale = service.getHandler('delete')(folderWithPermission, null, permission); expect(documentListService.deleteNode).toHaveBeenCalledWith(folder.entry.id); @@ -123,7 +145,12 @@ describe('FolderActionsService', () => { }); it('should not delete the folder node if there is no delete permission', (done) => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); service.permissionEvent.subscribe((permission) => { expect(permission).toBeDefined(); @@ -139,7 +166,12 @@ describe('FolderActionsService', () => { }); it('should call the error on the returned Observable if there is no delete permission', (done) => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let folder = new FolderNode(); let folderWithPermission: any = folder; @@ -156,7 +188,12 @@ describe('FolderActionsService', () => { }); it('should delete the folder node if there is the delete and others permission ', () => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let permission = 'delete'; let folder = new FolderNode(); @@ -168,7 +205,12 @@ describe('FolderActionsService', () => { }); it('should support deletion only folder node', () => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let permission = 'delete'; let file = new FileNode(); @@ -183,7 +225,12 @@ describe('FolderActionsService', () => { }); it('should require node id to delete', () => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let folder = new FolderNode(); folder.entry.id = null; @@ -192,8 +239,13 @@ describe('FolderActionsService', () => { expect(documentListService.deleteNode).not.toHaveBeenCalled(); }); - it('should reload target upon node deletion', () => { - spyOn(documentListService, 'deleteNode').and.callThrough(); + it('should reload target upon node deletion', (done) => { + spyOn(documentListService, 'deleteNode').and.callFake(() => { + return new Observable(observer => { + observer.next(); + observer.complete(); + }); + }); let permission = 'delete'; let target = jasmine.createSpyObj('obj', ['reload']); @@ -201,9 +253,13 @@ describe('FolderActionsService', () => { let folderWithPermission: any = folder; folderWithPermission.entry.allowableOperations = [permission]; - service.getHandler('delete')(folderWithPermission, target, permission); + let deleteHandler = service.getHandler('delete')(folderWithPermission, target, permission); + + deleteHandler.subscribe(() => { + expect(target.reload).toHaveBeenCalled(); + done(); + }); expect(documentListService.deleteNode).toHaveBeenCalled(); - expect(target.reload).toHaveBeenCalled(); }); }); diff --git a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts index 4e1b11fb87..465f7c17de 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/services/folder-actions.service.ts @@ -16,6 +16,7 @@ */ import { Injectable } from '@angular/core'; +import { AlfrescoContentService } from 'ng2-alfresco-core'; import { Observable, Subject } from 'rxjs/Rx'; import { ContentActionHandler } from '../models/content-action.model'; import { PermissionModel } from '../models/permissions.model'; @@ -28,7 +29,8 @@ export class FolderActionsService { private handlers: { [id: string]: ContentActionHandler; } = {}; - constructor(private documentListService?: DocumentListService) { + constructor(private documentListService: DocumentListService, + private contentService: AlfrescoContentService) { this.setupActionHandlers(); } @@ -87,32 +89,21 @@ export class FolderActionsService { } private deleteNode(obj: any, target?: any, permission?: string): Observable { - let handlerObservale: Observable; + let handlerObservable: Observable; if (this.canExecuteAction(obj)) { - if (this.hasPermission(obj.entry, permission)) { - handlerObservale = this.documentListService.deleteNode(obj.entry.id); - handlerObservale.subscribe(() => { + if (this.contentService.hasPermission(obj.entry, permission)) { + handlerObservable = this.documentListService.deleteNode(obj.entry.id); + handlerObservable.subscribe(() => { if (target && typeof target.reload === 'function') { target.reload(); } }); - return handlerObservale; + return handlerObservable; } else { this.permissionEvent.next(new PermissionModel({type: 'folder', action: 'delete', permission: permission})); return Observable.throw(new Error('No permission to delete')); } } } - - private hasPermission(node: any, permissionToCheck: string): boolean { - if (this.hasPermissions(node)) { - return node.allowableOperations.find(permision => permision === permissionToCheck) ? true : false; - } - return false; - } - - private hasPermissions(node: any): boolean { - return node && node.allowableOperations ? true : false; - } }