mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-1040] Change document list style rows based on permissions model (#2085)
* Change document list style rows based on permissions model * fix test
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
</ng-container>
|
||||
<adf-document-list
|
||||
#documentList
|
||||
[permissionsStyle]="permissionsStyle"
|
||||
[creationMenuActions]="!useCustomToolbar"
|
||||
[currentFolderId]="currentFolderId"
|
||||
[contextMenuActions]="true"
|
||||
|
@@ -19,7 +19,7 @@ import { ChangeDetectorRef, Component, Input, OnInit, Optional, ViewChild } from
|
||||
import { MdDialog } from '@angular/material';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { AlfrescoContentService, FileUploadCompleteEvent, FolderCreatedEvent, NotificationService, UploadService } from 'ng2-alfresco-core';
|
||||
import { DocumentListComponent } from 'ng2-alfresco-documentlist';
|
||||
import { DocumentListComponent, PermissionStyleModel } from 'ng2-alfresco-documentlist';
|
||||
|
||||
import { CreateFolderDialogComponent } from '../../dialogs/create-folder.dialog';
|
||||
|
||||
@@ -65,6 +65,8 @@ export class FilesComponent implements OnInit {
|
||||
@ViewChild(DocumentListComponent)
|
||||
documentList: DocumentListComponent;
|
||||
|
||||
permissionsStyle: PermissionStyleModel[] = [];
|
||||
|
||||
constructor(private changeDetector: ChangeDetectorRef,
|
||||
private notificationService: NotificationService,
|
||||
private uploadService: UploadService,
|
||||
|
@@ -39,8 +39,7 @@ module.exports = {
|
||||
loader: 'tslint-loader',
|
||||
options: {
|
||||
emitErrors: true,
|
||||
failOnHint: true,
|
||||
fix:true
|
||||
failOnHint: true
|
||||
},
|
||||
exclude: [/node_modules/, /bundles/, /dist/, /demo/]
|
||||
},
|
||||
|
@@ -117,7 +117,11 @@ export * from './src/events/base.event';
|
||||
export * from './src/events/base-ui.event';
|
||||
export * from './src/events/folder-created.event';
|
||||
export * from './src/events/file.event';
|
||||
export * from './src/models/index';
|
||||
|
||||
export * from './src/models/card-view-textitem.model';
|
||||
export * from './src/models/card-view-dateitem.model';
|
||||
export * from './src/models/file.model';
|
||||
export * from './src/models/permissions.enum';
|
||||
|
||||
export * from './src/models/index';
|
||||
|
||||
|
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
|
||||
<path fill="#000" fill-opacity=".28" fill-rule="evenodd" d="M8 0H2C.9 0 0 .9 0 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2h-8L8 0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 239 B |
@@ -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';
|
||||
}
|
@@ -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();
|
||||
});
|
||||
});
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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 {
|
||||
|
@@ -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)">
|
||||
|
||||
<!-- Actions (left) -->
|
||||
<td *ngIf="actions && actionsPosition === 'left'">
|
||||
|
@@ -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}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ export interface DataTableAdapter {
|
||||
export interface DataRow {
|
||||
isSelected: boolean;
|
||||
isDropTarget?: boolean;
|
||||
cssClass?: string;
|
||||
hasValue(key: string): boolean;
|
||||
getValue(key: string): any;
|
||||
}
|
||||
|
@@ -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:
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
<adf-document-list [permissionsStyle]="permissionsStyle">
|
||||
</adf-document-list>
|
||||
```
|
||||
|
||||
```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
|
||||
<adf-document-list [permissionsStyle]="permissionsStyle">
|
||||
</adf-document-list>
|
||||
```
|
||||
|
||||
```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:
|
||||
|
@@ -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,
|
||||
|
@@ -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'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -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 = <ContentActionHandler> function (obj: any, target?: any) {};
|
||||
let handler = <ContentActionHandler> 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 = <ContentActionHandler> function (obj: any, target?: any) {};
|
||||
let handler = <ContentActionHandler> 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);
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
]
|
||||
});
|
||||
|
@@ -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) {
|
||||
|
@@ -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 = <DataColumn> {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 = <DataColumn> {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 = <DataColumn> {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 = <DataColumn> {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 = <DataColumn> {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 = <DataColumn> {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();
|
||||
});
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -103,32 +103,21 @@ export class DocumentActionsService {
|
||||
}
|
||||
|
||||
private deleteNode(obj: any, target?: any, permission?: string): Observable<any> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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('<key>', handler);
|
||||
expect(service.getHandler('<key>')).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('<key>', handler);
|
||||
expect(service.getHandler('<KEY>')).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<any>(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<any>(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<any>(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<any>(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<any>(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<any>(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<any>(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();
|
||||
});
|
||||
});
|
||||
|
@@ -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<any> {
|
||||
let handlerObservale: Observable<any>;
|
||||
let handlerObservable: Observable<any>;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user