mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-1002] Move the UploadService from the upload to core component and share it with the Process service (#2055)
* use the same upload component between the content and process service * Create a BaseUploadServe inside the core The AlfrescoUpload should extend the BaseUpload * Improve the code * Move the process service from the demo shell to form component * Merge [ADF-917] added exlcluded files into app config to prevent special files * Remove typo * Fix import * Fix FileModel import * Fix Denys comment * Fix unit test with the new path of UploadService * Add missing implementation
This commit is contained in:
committed by
Eugenio Romano
parent
dd61cf7b45
commit
183dd3c990
@@ -66,7 +66,7 @@ npm install ng2-alfresco-upload
|
||||
|
||||
```html
|
||||
<adf-upload-button
|
||||
[rootFolderId]="-my-"
|
||||
[parentId]="-my-"
|
||||
[uploadFolders]="true"
|
||||
[multipleFiles]="false"
|
||||
[acceptedFilesType]=".jpg,.gif,.png,.svg"
|
||||
@@ -86,7 +86,9 @@ npm install ng2-alfresco-upload
|
||||
| multipleFiles | boolean | false | Allow/disallow multiple files |
|
||||
| acceptedFilesType | string | * | array of allowed file extensions , example: ".jpg,.gif,.png,.svg" |
|
||||
| **(deprecated)** currentFolderPath | string | '/Sites/swsdp/documentLibrary' | define the path where the files are uploaded. **Deprecated in 1.6.0: use rootFolderId instead.** |
|
||||
| rootFolderId | string | '-root-' | The ID of the root folder node. |
|
||||
| **(deprecated)** rootFolderId | string | '-root-' | The ID of the root folder node.
|
||||
**Deprecated in 1.6.2: use parentId instead.** |
|
||||
| parentId | string | empty | The ID of the root. It can be the nodeId if you are using the upload for the Content Service or taskId/processId for the Process Service. |
|
||||
| versioning | boolean | false | Versioning false is the default uploader behaviour and it rename using an integer suffix if there is a name clash. Versioning true to indicate that a major version should be created |
|
||||
| staticTitle | string | (predefined) | define the text of the upload button |
|
||||
| disableWithNoPermission | boolean | false | If the value is true and the user doesn't have the permission to delete the node the button will be disabled |
|
||||
|
@@ -24,17 +24,13 @@ import { FileUploadingListComponent } from './src/components/file-uploading-list
|
||||
import { UploadButtonComponent } from './src/components/upload-button.component';
|
||||
import { UploadDragAreaComponent } from './src/components/upload-drag-area.component';
|
||||
import { FileDraggableDirective } from './src/directives/file-draggable.directive';
|
||||
import { UploadService } from './src/services/upload.service';
|
||||
|
||||
export * from './src/components/upload-button.component';
|
||||
export * from './src/components/file-uploading-dialog.component';
|
||||
export * from './src/components/upload-drag-area.component';
|
||||
export * from './src/services/upload.service';
|
||||
export * from './src/directives/file-draggable.directive';
|
||||
export * from './src/components/file-uploading-list.component';
|
||||
export * from './src/models/file.model';
|
||||
export * from './src/models/permissions.model';
|
||||
export * from './src/events/file.event';
|
||||
|
||||
export const UPLOAD_DIRECTIVES: any[] = [
|
||||
FileDraggableDirective,
|
||||
@@ -45,7 +41,7 @@ export const UPLOAD_DIRECTIVES: any[] = [
|
||||
];
|
||||
|
||||
export const UPLOAD_PROVIDERS: any[] = [
|
||||
UploadService
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@@ -21,9 +21,8 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { FileUploadingDialogComponent } from './file-uploading-dialog.component';
|
||||
import { FileUploadingListComponent } from './file-uploading-list.component';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { FileModel, FileUploadStatus } from '../models/file.model';
|
||||
import { FileUploadCompleteEvent, FileUploadEvent } from '../events/file.event';
|
||||
import { FileModel, FileUploadStatus } from 'ng2-alfresco-core';
|
||||
import { FileUploadCompleteEvent, FileUploadEvent, UploadService } from 'ng2-alfresco-core';
|
||||
|
||||
describe('FileUploadingDialogComponent', () => {
|
||||
|
||||
|
@@ -16,10 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||
import { FileUploadCompleteEvent } from '../events/file.event';
|
||||
import { FileModel, FileUploadStatus } from '../models/file.model';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { AlfrescoTranslationService, FileModel, FileUploadCompleteEvent, FileUploadStatus, UploadService } from 'ng2-alfresco-core';
|
||||
|
||||
@Component({
|
||||
selector: 'file-uploading-dialog',
|
||||
|
@@ -16,8 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { FileModel, FileUploadStatus } from '../models/file.model';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { FileModel, FileUploadStatus, UploadService } from 'ng2-alfresco-core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-file-uploading-list, alfresco-file-uploading-list',
|
||||
|
@@ -18,9 +18,8 @@
|
||||
import { DebugElement, SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { UploadButtonComponent } from './upload-button.component';
|
||||
import { CoreModule, AlfrescoTranslationService, AlfrescoContentService} from 'ng2-alfresco-core';
|
||||
import { CoreModule, AlfrescoTranslationService, AlfrescoContentService, UploadService } from 'ng2-alfresco-core';
|
||||
import { TranslationMock } from '../assets/translation.service.mock';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
describe('UploadButtonComponent', () => {
|
||||
|
@@ -17,11 +17,9 @@
|
||||
|
||||
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { AlfrescoApiService, AlfrescoContentService, AlfrescoTranslationService, FileUtils, LogService, NotificationService } from 'ng2-alfresco-core';
|
||||
import { AlfrescoApiService, AlfrescoContentService, AlfrescoTranslationService, FileModel, FileUtils, LogService, NotificationService, UploadService } from 'ng2-alfresco-core';
|
||||
import { Observable, Subject } from 'rxjs/Rx';
|
||||
import { FileModel } from '../models/file.model';
|
||||
import { PermissionModel } from '../models/permissions.model';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-upload-button, alfresco-upload-button',
|
||||
|
@@ -17,13 +17,11 @@
|
||||
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { AlfrescoTranslationService, CoreModule, LogService, LogServiceMock } from 'ng2-alfresco-core';
|
||||
import { AlfrescoTranslationService, CoreModule, FileModel, LogService, LogServiceMock, UploadService } from 'ng2-alfresco-core';
|
||||
|
||||
import { UploadDragAreaComponent } from './upload-drag-area.component';
|
||||
import { FileDraggableDirective } from '../directives/file-draggable.directive';
|
||||
import { TranslationMock } from '../assets/translation.service.mock';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { FileModel } from '../models/file.model';
|
||||
|
||||
let fakeShareDataRow = {
|
||||
obj: {
|
||||
|
@@ -16,9 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { AlfrescoTranslationService, FileInfo, FileUtils, NotificationService } from 'ng2-alfresco-core';
|
||||
import { FileModel } from '../models/file.model';
|
||||
import { UploadService } from '../services/upload.service';
|
||||
import { AlfrescoTranslationService, FileInfo, FileModel, FileUtils, NotificationService, UploadService } from 'ng2-alfresco-core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-upload-drag-area, alfresco-upload-drag-area',
|
||||
@@ -60,9 +58,18 @@ export class UploadDragAreaComponent {
|
||||
@Input()
|
||||
currentFolderPath: string = '/';
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated in 1.6.2, this property is not used for couple of releases already. Use parentId instead.
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UploadDragAreaComponent
|
||||
*/
|
||||
@Input()
|
||||
rootFolderId: string = '-root-';
|
||||
|
||||
@Input()
|
||||
parentId: string;
|
||||
|
||||
@Output()
|
||||
onSuccess = new EventEmitter();
|
||||
|
||||
@@ -85,9 +92,9 @@ export class UploadDragAreaComponent {
|
||||
if (isAllowed) {
|
||||
let files: FileInfo[] = event.detail.files;
|
||||
if (files && files.length > 0) {
|
||||
let parentId = this.rootFolderId;
|
||||
let parentId = this.parentId || this.rootFolderId;
|
||||
if (event.detail.data && event.detail.data.obj.entry.isFolder) {
|
||||
parentId = event.detail.data.obj.entry.id || this.rootFolderId;
|
||||
parentId = event.detail.data.obj.entry.id || this.parentId || this.rootFolderId;
|
||||
}
|
||||
const fileModels = files.map(fileInfo => new FileModel(fileInfo.file, {
|
||||
newVersion: this.versioning,
|
||||
@@ -109,7 +116,7 @@ export class UploadDragAreaComponent {
|
||||
const fileModels = files.map(file => new FileModel(file, {
|
||||
newVersion: this.versioning,
|
||||
path: '/',
|
||||
parentId: this.rootFolderId
|
||||
parentId: this.parentId || this.rootFolderId
|
||||
}));
|
||||
this.uploadService.addToQueue(...fileModels);
|
||||
this.uploadService.uploadFilesInTheQueue(this.onSuccess);
|
||||
@@ -129,7 +136,7 @@ export class UploadDragAreaComponent {
|
||||
item.file((file: File) => {
|
||||
const fileModel = new FileModel(file, {
|
||||
newVersion: this.versioning,
|
||||
parentId: this.rootFolderId,
|
||||
parentId: this.parentId || this.rootFolderId,
|
||||
path: item.fullPath.replace(item.name, '')
|
||||
});
|
||||
this.uploadService.addToQueue(fileModel);
|
||||
@@ -151,7 +158,7 @@ export class UploadDragAreaComponent {
|
||||
let files = entries.map(entry => {
|
||||
return new FileModel(entry.file, {
|
||||
newVersion: this.versioning,
|
||||
parentId: this.rootFolderId,
|
||||
parentId: this.parentId || this.rootFolderId,
|
||||
path: entry.relativeFolder
|
||||
});
|
||||
});
|
||||
|
@@ -1,36 +0,0 @@
|
||||
/*!
|
||||
* @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 { FileModel, FileUploadStatus } from '../models/file.model';
|
||||
|
||||
export class FileUploadEvent {
|
||||
|
||||
constructor(
|
||||
public readonly file: FileModel,
|
||||
public readonly status: FileUploadStatus = FileUploadStatus.Pending,
|
||||
public readonly error: any = null) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FileUploadCompleteEvent extends FileUploadEvent {
|
||||
|
||||
constructor(file: FileModel, public totalComplete: number = 0, public data?: any, public totalAborted: number = 0) {
|
||||
super(file, FileUploadStatus.Complete);
|
||||
}
|
||||
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export interface FileUploadProgress {
|
||||
loaded: number;
|
||||
total: number;
|
||||
percent: number;
|
||||
}
|
||||
|
||||
export interface FileUploadOptions {
|
||||
newVersion?: boolean;
|
||||
parentId?: string;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export enum FileUploadStatus {
|
||||
Pending = 0,
|
||||
Complete = 1,
|
||||
Starting = 2,
|
||||
Progress = 3,
|
||||
Cancelled = 4,
|
||||
Aborted = 5,
|
||||
Error = 6
|
||||
}
|
||||
|
||||
export class FileModel {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly size: number;
|
||||
readonly file: File;
|
||||
|
||||
status: FileUploadStatus = FileUploadStatus.Pending;
|
||||
progress: FileUploadProgress;
|
||||
options: FileUploadOptions;
|
||||
|
||||
constructor(file: File, options?: FileUploadOptions) {
|
||||
this.file = file;
|
||||
|
||||
this.id = this.generateId();
|
||||
this.name = file.name;
|
||||
this.size = file.size;
|
||||
|
||||
this.progress = {
|
||||
loaded: 0,
|
||||
total: 0,
|
||||
percent: 0
|
||||
};
|
||||
|
||||
this.options = Object.assign({}, {
|
||||
newVersion: false
|
||||
}, options);
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,210 +0,0 @@
|
||||
/*!
|
||||
* @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 { EventEmitter } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CoreModule, AppConfigModule } from 'ng2-alfresco-core';
|
||||
import { UploadService } from './upload.service';
|
||||
import { FileModel, FileUploadOptions } from '../models/file.model';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('UploadService', () => {
|
||||
let service: UploadService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot(),
|
||||
AppConfigModule.forRoot('app.config.json', {
|
||||
ecmHost: 'http://localhost:9876/ecm',
|
||||
files: {
|
||||
excluded: ['.DS_Store', 'desktop.ini', '.git', '*.git']
|
||||
}
|
||||
})
|
||||
],
|
||||
providers: [
|
||||
UploadService
|
||||
]
|
||||
});
|
||||
service = TestBed.get(UploadService);
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should return an empty queue if no elements are added', () => {
|
||||
expect(service.getQueue().length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should add an element in the queue and returns it', () => {
|
||||
let filesFake = new FileModel(<File>{ name: 'fake-name', size: 10 });
|
||||
service.addToQueue(filesFake);
|
||||
expect(service.getQueue().length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add two elements in the queue and returns them', () => {
|
||||
let filesFake = [
|
||||
new FileModel(<File>{ name: 'fake-name', size: 10 }),
|
||||
new FileModel(<File>{ name: 'fake-name2', size: 20 })
|
||||
];
|
||||
service.addToQueue(...filesFake);
|
||||
expect(service.getQueue().length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should skip hidden macOS files', () => {
|
||||
const file1 = new FileModel(new File([''], '.git'));
|
||||
const file2 = new FileModel(new File([''], 'readme.md'));
|
||||
const result = service.addToQueue(file1, file2);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result[0]).toBe(file2);
|
||||
});
|
||||
|
||||
it('should make XHR done request after the file is added in the queue', (done) => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
emitter.subscribe(e => {
|
||||
expect(e.value).toBe('File uploaded');
|
||||
done();
|
||||
});
|
||||
let fileFake = new FileModel(
|
||||
<File>{ name: 'fake-name', size: 10 },
|
||||
<FileUploadOptions>{ parentId: '-root-', path: 'fake-dir' }
|
||||
);
|
||||
service.addToQueue(fileFake);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
|
||||
let request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toBe('http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-/children?autoRename=true');
|
||||
expect(request.method).toBe('POST');
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 200,
|
||||
contentType: 'text/plain',
|
||||
responseText: 'File uploaded'
|
||||
});
|
||||
});
|
||||
|
||||
it('should make XHR error request after an error occur', (done) => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
emitter.subscribe(e => {
|
||||
expect(e.value).toBe('Error file uploaded');
|
||||
done();
|
||||
});
|
||||
let fileFake = new FileModel(
|
||||
<File>{ name: 'fake-name', size: 10 },
|
||||
<FileUploadOptions>{ parentId: '-root-' }
|
||||
);
|
||||
service.addToQueue(fileFake);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
expect(jasmine.Ajax.requests.mostRecent().url)
|
||||
.toBe('http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-/children?autoRename=true');
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 404,
|
||||
contentType: 'text/plain',
|
||||
responseText: 'Error file uploaded'
|
||||
});
|
||||
});
|
||||
|
||||
it('should make XHR abort request after the xhr abort is called', (done) => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
emitter.subscribe(e => {
|
||||
expect(e.value).toEqual('File aborted');
|
||||
done();
|
||||
});
|
||||
let fileFake = new FileModel(<File>{ name: 'fake-name', size: 10 });
|
||||
service.addToQueue(fileFake);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
|
||||
let file = service.getQueue();
|
||||
service.cancelUpload(...file);
|
||||
});
|
||||
|
||||
it('If versioning is true autoRename should not be present and majorVersion should be a param', () => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
const filesFake = new FileModel(<File>{ name: 'fake-name', size: 10 }, { newVersion: true });
|
||||
service.addToQueue(filesFake);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('autoRename=true')).toBe(false);
|
||||
expect(jasmine.Ajax.requests.mostRecent().params.has('majorVersion')).toBe(true);
|
||||
});
|
||||
|
||||
it('should use custom root folder ID given to the service', (done) => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
emitter.subscribe(e => {
|
||||
expect(e.value).toBe('File uploaded');
|
||||
done();
|
||||
});
|
||||
let filesFake = new FileModel(
|
||||
<File>{ name: 'fake-name', size: 10 },
|
||||
<FileUploadOptions> { parentId: '123', path: 'fake-dir' }
|
||||
);
|
||||
service.addToQueue(filesFake);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
|
||||
let request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toBe('http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/123/children?autoRename=true');
|
||||
expect(request.method).toBe('POST');
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 200,
|
||||
contentType: 'text/plain',
|
||||
responseText: 'File uploaded'
|
||||
});
|
||||
});
|
||||
|
||||
it('should start downloading the next one if a file of the list is aborted', (done) => {
|
||||
let emitter = new EventEmitter();
|
||||
|
||||
service.fileUploadAborted.subscribe(e => {
|
||||
expect(e).not.toBeNull();
|
||||
});
|
||||
|
||||
service.fileUploadCancelled.subscribe(e => {
|
||||
expect(e).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
|
||||
let fileFake1 = new FileModel(<File>{ name: 'fake-name1', size: 10 });
|
||||
let fileFake2 = new FileModel(<File>{ name: 'fake-name2', size: 10 });
|
||||
let filelist = [fileFake1, fileFake2];
|
||||
service.addToQueue(...filelist);
|
||||
service.uploadFilesInTheQueue(emitter);
|
||||
|
||||
let file = service.getQueue();
|
||||
service.cancelUpload(...file);
|
||||
});
|
||||
|
||||
it('should remove from the queue all the files in the exluded list', () => {
|
||||
const file1 = new FileModel(new File([''], '.git'));
|
||||
const file2 = new FileModel(new File([''], '.DS_Store'));
|
||||
const file3 = new FileModel(new File([''], 'desktop.ini'));
|
||||
const file4 = new FileModel(new File([''], 'readme.md'));
|
||||
const file5 = new FileModel(new File([''], 'test.git'));
|
||||
const result = service.addToQueue(file1, file2, file3, file4, file5);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result[0]).toBe(file4);
|
||||
});
|
||||
});
|
@@ -1,251 +0,0 @@
|
||||
/*!
|
||||
* @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 { EventEmitter, Injectable } from '@angular/core';
|
||||
import * as minimatch from 'minimatch';
|
||||
import { AlfrescoApiService, AppConfigService } from 'ng2-alfresco-core';
|
||||
import { Subject } from 'rxjs/Rx';
|
||||
import { FileUploadCompleteEvent, FileUploadEvent } from '../events/file.event';
|
||||
import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model';
|
||||
|
||||
@Injectable()
|
||||
export class UploadService {
|
||||
|
||||
private queue: FileModel[] = [];
|
||||
private cache: { [key: string]: any } = {};
|
||||
private totalComplete: number = 0;
|
||||
private totalAborted: number = 0;
|
||||
private activeTask: Promise<any> = null;
|
||||
private excludedFileList: String[] = [];
|
||||
|
||||
queueChanged: Subject<FileModel[]> = new Subject<FileModel[]>();
|
||||
fileUpload: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadStarting: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadCancelled: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadProgress: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadAborted: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadError: Subject<FileUploadEvent> = new Subject<FileUploadEvent>();
|
||||
fileUploadComplete: Subject<FileUploadCompleteEvent> = new Subject<FileUploadCompleteEvent>();
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private appConfigService: AppConfigService) {
|
||||
this.excludedFileList = <String[]>this.appConfigService.get('files.excluded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the service is uploading a file.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @memberof UploadService
|
||||
*/
|
||||
isUploading(): boolean {
|
||||
return this.activeTask ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file Queue
|
||||
*
|
||||
* @return {FileModel[]} - files in the upload queue.
|
||||
*/
|
||||
getQueue(): FileModel[] {
|
||||
return this.queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add files to the uploading queue to be uploaded.
|
||||
*
|
||||
* Examples:
|
||||
* addToQueue(file); // pass one file
|
||||
* addToQueue(file1, file2, file3); // pass multiple files
|
||||
* addToQueue(...[file1, file2, file3]); // pass an array of files
|
||||
*/
|
||||
addToQueue(...files: FileModel[]): FileModel[] {
|
||||
const allowedFiles = files.filter(f => this.filterElement(f));
|
||||
this.queue = this.queue.concat(allowedFiles);
|
||||
this.queueChanged.next(this.queue);
|
||||
return allowedFiles;
|
||||
}
|
||||
|
||||
private filterElement(file: FileModel) {
|
||||
let isAllowed = true;
|
||||
if (this.excludedFileList) {
|
||||
isAllowed = this.excludedFileList.filter(expr => minimatch(file.name, expr)).length === 0;
|
||||
}
|
||||
return isAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick all the files in the queue that are not been uploaded yet and upload it into the directory folder.
|
||||
*
|
||||
* @param {EventEmitter<any>} emitter @deprecated emitter to invoke on file status change
|
||||
*
|
||||
* @memberof UploadService
|
||||
*/
|
||||
uploadFilesInTheQueue(emitter: EventEmitter<any>): void {
|
||||
if (!this.activeTask) {
|
||||
let file = this.queue.find(f => f.status === FileUploadStatus.Pending);
|
||||
if (file) {
|
||||
this.onUploadStarting(file);
|
||||
|
||||
const promise = this.beginUpload(file, emitter);
|
||||
this.activeTask = promise;
|
||||
this.cache[file.id] = promise;
|
||||
|
||||
let next = () => {
|
||||
this.activeTask = null;
|
||||
setTimeout(() => this.uploadFilesInTheQueue(emitter), 100);
|
||||
};
|
||||
|
||||
promise.next = next;
|
||||
|
||||
promise.then(
|
||||
() => next(),
|
||||
() => next()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cancelUpload(...files: FileModel[]) {
|
||||
files.forEach(file => {
|
||||
file.status = FileUploadStatus.Cancelled;
|
||||
|
||||
const promise = this.cache[file.id];
|
||||
if (promise) {
|
||||
promise.abort();
|
||||
delete this.cache[file.id];
|
||||
}
|
||||
|
||||
const event = new FileUploadEvent(file, FileUploadStatus.Cancelled);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadCancelled.next(event);
|
||||
});
|
||||
}
|
||||
|
||||
clearQueue() {
|
||||
this.queue = [];
|
||||
this.totalComplete = 0;
|
||||
this.totalAborted = 0;
|
||||
}
|
||||
|
||||
private beginUpload(file: FileModel, /* @deprecated */emitter: EventEmitter<any>): any {
|
||||
let opts: any = {
|
||||
renditions: 'doclib'
|
||||
};
|
||||
|
||||
if (file.options.newVersion === true) {
|
||||
opts.overwrite = true;
|
||||
opts.majorVersion = true;
|
||||
} else {
|
||||
opts.autoRename = true;
|
||||
}
|
||||
let promise = this.apiService.getInstance().upload.uploadFile(
|
||||
file.file,
|
||||
file.options.path,
|
||||
file.options.parentId,
|
||||
null,
|
||||
opts
|
||||
);
|
||||
promise.on('progress', (progress: FileUploadProgress) => {
|
||||
this.onUploadProgress(file, progress);
|
||||
})
|
||||
.on('abort', () => {
|
||||
this.onUploadAborted(file);
|
||||
emitter.emit({ value: 'File aborted' });
|
||||
})
|
||||
.on('error', err => {
|
||||
this.onUploadError(file, err);
|
||||
emitter.emit({ value: 'Error file uploaded' });
|
||||
})
|
||||
.on('success', data => {
|
||||
this.onUploadComplete(file, data);
|
||||
emitter.emit({ value: data });
|
||||
})
|
||||
.catch(err => {
|
||||
this.onUploadError(file, err);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
private onUploadStarting(file: FileModel): void {
|
||||
if (file) {
|
||||
file.status = FileUploadStatus.Starting;
|
||||
const event = new FileUploadEvent(file, FileUploadStatus.Starting);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadStarting.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadProgress(file: FileModel, progress: FileUploadProgress): void {
|
||||
if (file) {
|
||||
file.progress = progress;
|
||||
file.status = FileUploadStatus.Progress;
|
||||
|
||||
const event = new FileUploadEvent(file, FileUploadStatus.Progress);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadProgress.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadError(file: FileModel, error: any): void {
|
||||
if (file) {
|
||||
file.status = FileUploadStatus.Error;
|
||||
|
||||
const promise = this.cache[file.id];
|
||||
if (promise) {
|
||||
delete this.cache[file.id];
|
||||
}
|
||||
|
||||
const event = new FileUploadEvent(file, FileUploadStatus.Error, error);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadError.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadComplete(file: FileModel, data: any): void {
|
||||
if (file) {
|
||||
file.status = FileUploadStatus.Complete;
|
||||
this.totalComplete++;
|
||||
|
||||
const promise = this.cache[file.id];
|
||||
if (promise) {
|
||||
delete this.cache[file.id];
|
||||
}
|
||||
|
||||
const event = new FileUploadCompleteEvent(file, this.totalComplete, data, this.totalAborted);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadComplete.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
private onUploadAborted(file: FileModel): void {
|
||||
if (file) {
|
||||
file.status = FileUploadStatus.Aborted;
|
||||
this.totalAborted++;
|
||||
|
||||
const promise = this.cache[file.id];
|
||||
if (promise) {
|
||||
delete this.cache[file.id];
|
||||
}
|
||||
|
||||
const event = new FileUploadEvent(file, FileUploadStatus.Aborted);
|
||||
this.fileUpload.next(event);
|
||||
this.fileUploadAborted.next(event);
|
||||
promise.next();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user