From 970806fb2025ab3158b50827995d2e84f170ce3d Mon Sep 17 00:00:00 2001 From: Pablo Martinez Garcia Date: Tue, 14 Sep 2021 09:41:41 +0200 Subject: [PATCH] Extract all the content --- demo-shell/src/app/app.module.ts | 7 +- .../process-attachments.component.ts | 8 +- .../task-attachments.component.ts | 8 +- .../content-node-share.directive.ts | 18 +- .../src/lib/dialogs/node-lock.dialog.ts | 16 +- .../components/document-list.component.ts | 14 +- .../services/custom-resources.service.ts | 296 +-------- .../services/document-list.service.ts | 21 +- .../services/node-actions.service.ts | 7 +- .../version-manager/version-list.component.ts | 40 +- lib/core/core.module.ts | 4 +- lib/core/directives/node-delete.directive.ts | 22 +- .../directives/node-download.directive.ts | 16 +- lib/core/services/acs-content.service.ts | 576 ++++++++++++++++++ lib/core/services/content-provider.service.ts | 191 ++++++ lib/core/services/content.service.ts | 484 ++++++++++++--- .../services/deleted-nodes-api.service.ts | 20 +- lib/core/services/nodes-api.service.ts | 34 +- lib/core/services/public-api.ts | 2 + lib/core/services/renditions.service.ts | 30 +- lib/core/services/thumbnail.service.ts | 14 +- lib/core/services/upload.service.ts | 31 +- .../viewer/components/viewer.component.ts | 72 +-- lib/core/viewer/services/view-util.service.ts | 58 +- .../attach-file-cloud-widget.component.ts | 16 +- .../content-cloud-node-selector.service.ts | 18 +- .../services/process-upload.service.ts | 11 +- .../task-list/services/task-upload.service.ts | 11 +- 28 files changed, 1363 insertions(+), 682 deletions(-) create mode 100644 lib/core/services/acs-content.service.ts create mode 100644 lib/core/services/content-provider.service.ts diff --git a/demo-shell/src/app/app.module.ts b/demo-shell/src/app/app.module.ts index c736763b8c..8623929fb0 100644 --- a/demo-shell/src/app/app.module.ts +++ b/demo-shell/src/app/app.module.ts @@ -29,7 +29,9 @@ import { DebugAppConfigService, CoreModule, CoreAutomationService, - AuthBearerInterceptor + AuthBearerInterceptor, + registerContentServiceProvider, + AcsContentService } from '@alfresco/adf-core'; import { ExtensionsModule } from '@alfresco/adf-extensions'; import { AppComponent } from './app.component'; @@ -236,7 +238,8 @@ registerLocaleData(localeSv); useFactory: setupAppNotifications, deps: [AppNotificationsService], multi: true - } + }, + registerContentServiceProvider(AcsContentService, true) ], bootstrap: [AppComponent] }) diff --git a/demo-shell/src/app/components/process-service/process-attachments.component.ts b/demo-shell/src/app/components/process-service/process-attachments.component.ts index 66b83cafac..10f9fc2636 100644 --- a/demo-shell/src/app/components/process-service/process-attachments.component.ts +++ b/demo-shell/src/app/components/process-service/process-attachments.component.ts @@ -18,13 +18,13 @@ import { Component, Input, OnChanges, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { ProcessInstance, ProcessService , ProcessAttachmentListComponent, ProcessUploadService } from '@alfresco/adf-process-services'; -import { UploadService, AlfrescoApiService, AppConfigService, DiscoveryApiService } from '@alfresco/adf-core'; +import { UploadService, AlfrescoApiService, AppConfigService, DiscoveryApiService, ContentService, AcsContentService } from '@alfresco/adf-core'; import { PreviewService } from '../../services/preview.service'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -export function processUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) { - return new ProcessUploadService(api, config, discoveryApiService); +export function processUploadServiceFactory(contentService: ContentService, api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) { + return new ProcessUploadService(contentService, api, config, discoveryApiService); } @Component({ @@ -35,7 +35,7 @@ export function processUploadServiceFactory(api: AlfrescoApiService, config: App { provide: UploadService, useFactory: (processUploadServiceFactory), - deps: [AlfrescoApiService, AppConfigService, DiscoveryApiService] + deps: [AcsContentService, AlfrescoApiService, AppConfigService, DiscoveryApiService] } ] }) diff --git a/demo-shell/src/app/components/process-service/task-attachments.component.ts b/demo-shell/src/app/components/process-service/task-attachments.component.ts index 38529272d5..ae1ca2c085 100644 --- a/demo-shell/src/app/components/process-service/task-attachments.component.ts +++ b/demo-shell/src/app/components/process-service/task-attachments.component.ts @@ -22,13 +22,13 @@ import { TaskUploadService, TaskDetailsModel } from '@alfresco/adf-process-services'; -import { UploadService, AlfrescoApiService, AppConfigService, DiscoveryApiService } from '@alfresco/adf-core'; +import { UploadService, AlfrescoApiService, AppConfigService, DiscoveryApiService, ContentService, AcsContentService } from '@alfresco/adf-core'; import { PreviewService } from '../../services/preview.service'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -export function taskUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) { - return new TaskUploadService(api, config, discoveryApiService); +export function taskUploadServiceFactory(contentService: ContentService, api: AlfrescoApiService, config: AppConfigService, discoveryApiService: DiscoveryApiService) { + return new TaskUploadService(contentService, api, config, discoveryApiService); } @Component({ @@ -39,7 +39,7 @@ export function taskUploadServiceFactory(api: AlfrescoApiService, config: AppCon { provide: UploadService, useFactory: (taskUploadServiceFactory), - deps: [AlfrescoApiService, AppConfigService, DiscoveryApiService] + deps: [AcsContentService, AlfrescoApiService, AppConfigService, DiscoveryApiService] } ] }) diff --git a/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts b/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts index 31381043ef..e91a053f3f 100644 --- a/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts +++ b/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts @@ -17,11 +17,11 @@ import { Directive, Input, HostListener, OnChanges, NgZone, OnDestroy } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { NodeEntry, NodesApi } from '@alfresco/js-api'; +import { NodeEntry } from '@alfresco/js-api'; import { ShareDialogComponent } from './content-node-share.dialog'; -import { Observable, from, Subject } from 'rxjs'; -import { AlfrescoApiService } from '@alfresco/adf-core'; +import { Observable, Subject } from 'rxjs'; +import { ContentService } from '@alfresco/adf-core'; import { takeUntil } from 'rxjs/operators'; @Directive({ @@ -44,16 +44,10 @@ export class NodeSharedDirective implements OnChanges, OnDestroy { private onDestroy$ = new Subject(); - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance()); - return this._nodesApi; - } - - constructor( + constructor( private dialog: MatDialog, private zone: NgZone, - private alfrescoApiService: AlfrescoApiService) { + private contentService: ContentService) { } ngOnDestroy() { @@ -81,7 +75,7 @@ export class NodeSharedDirective implements OnChanges, OnDestroy { include: ['allowableOperations'] }; - return from(this.nodesApi.getNode(nodeId, options)); + return this.contentService.getNode(nodeId, options); } private openShareLinkDialog(node: NodeEntry) { diff --git a/lib/content-services/src/lib/dialogs/node-lock.dialog.ts b/lib/content-services/src/lib/dialogs/node-lock.dialog.ts index 17037dc7ba..21678c4285 100644 --- a/lib/content-services/src/lib/dialogs/node-lock.dialog.ts +++ b/lib/content-services/src/lib/dialogs/node-lock.dialog.ts @@ -21,8 +21,8 @@ import { Component, Inject, OnInit, Optional, ViewEncapsulation } from '@angular import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { NodeBodyLock, Node, NodeEntry, NodesApi } from '@alfresco/js-api'; -import { AlfrescoApiService } from '@alfresco/adf-core'; +import { NodeBodyLock, Node, NodeEntry } from '@alfresco/js-api'; +import { ContentService } from '@alfresco/adf-core'; @Component({ selector: 'adf-node-lock', @@ -35,16 +35,10 @@ export class NodeLockDialogComponent implements OnInit { node: Node = null; nodeName: string; - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApi.getInstance()); - return this._nodesApi; - } - constructor( private formBuilder: FormBuilder, public dialog: MatDialogRef, - private alfrescoApi: AlfrescoApiService, + private contentService: ContentService, @Optional() @Inject(MAT_DIALOG_DATA) public data: any @@ -84,10 +78,10 @@ export class NodeLockDialogComponent implements OnInit { const { data: { node } } = this; if (this.form.value.isLocked) { - return this.nodesApi.lockNode(node.id, this.nodeBodyLock); + return this.contentService.lockNode(node.id, this.nodeBodyLock); } - return this.nodesApi.unlockNode(node.id); + return this.contentService.unlockNode(node.id); } submit(): void { diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.ts b/lib/content-services/src/lib/document-list/components/document-list.component.ts index f581beac8d..4352902cfa 100644 --- a/lib/content-services/src/lib/document-list/components/document-list.component.ts +++ b/lib/content-services/src/lib/document-list/components/document-list.component.ts @@ -42,13 +42,12 @@ import { CustomNoPermissionTemplateDirective, CustomEmptyContentTemplateDirective, RequestPaginationModel, - AlfrescoApiService, UserPreferenceValues, LockService, DataRow } from '@alfresco/adf-core'; -import { Node, NodeEntry, NodePaging, NodesApi, Pagination } from '@alfresco/js-api'; +import { Node, NodeEntry, NodePaging, Pagination } from '@alfresco/js-api'; import { Subject, BehaviorSubject, of } from 'rxjs'; import { ShareDataRow } from './../data/share-data-row.model'; import { ShareDataTableAdapter } from './../data/share-datatable-adapter'; @@ -343,12 +342,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte private loadingTimeout; private onDestroy$ = new Subject(); - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance()); - return this._nodesApi; - } - constructor(private documentListService: DocumentListService, private ngZone: NgZone, private elementRef: ElementRef, @@ -356,7 +349,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte private userPreferencesService: UserPreferencesService, private contentService: ContentService, private thumbnailService: ThumbnailService, - private alfrescoApiService: AlfrescoApiService, private lockService: LockService) { this.userPreferencesService .select(UserPreferenceValues.PaginationSize) @@ -807,8 +799,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte include: this.includeFields }; - this.nodesApi.getNode(nodeEntry.entry['guid'], options) - .then((node: NodeEntry) => { + this.contentService.getNode(nodeEntry.entry['guid'], options).subscribe( + (node: NodeEntry) => { this.navigateTo(node.entry); }); } diff --git a/lib/content-services/src/lib/document-list/services/custom-resources.service.ts b/lib/content-services/src/lib/document-list/services/custom-resources.service.ts index 451969e307..60a95a92c1 100644 --- a/lib/content-services/src/lib/document-list/services/custom-resources.service.ts +++ b/lib/content-services/src/lib/document-list/services/custom-resources.service.ts @@ -15,75 +15,27 @@ * limitations under the License. */ -import { AlfrescoApiService, LogService, PaginationModel } from '@alfresco/adf-core'; +import { ContentService, LogService, PaginationModel } from '@alfresco/adf-core'; import { NodePaging, DeletedNodesPaging, - SearchRequest, SharedLinkPaging, - FavoritePaging, - SiteMemberPaging, - SiteRolePaging, - PeopleApi, - SitesApi, - SearchApi, - FavoritesApi, - SharedlinksApi, - TrashcanApi, - NodesApi + SiteMemberPaging } from '@alfresco/js-api'; import { Injectable } from '@angular/core'; -import { Observable, from, of, throwError } from 'rxjs'; +import { Observable, of, throwError } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class CustomResourcesService { - private CREATE_PERMISSION = 'create'; - - _peopleApi: PeopleApi; - get peopleApi(): PeopleApi { - this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance()); - return this._peopleApi; + constructor(private contentService: ContentService, private logService: LogService) { } - _sitesApi: SitesApi; - get sitesApi(): SitesApi { - this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance()); - return this._sitesApi; - } - - _trashcanApi: TrashcanApi; - get trashcanApi(): TrashcanApi { - this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance()); - return this._trashcanApi; - } - - _searchApi: SearchApi; - get searchApi(): SearchApi { - this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance()); - return this._searchApi; - } - - _sharedLinksApi: SharedlinksApi; - get sharedLinksApi(): SharedlinksApi { - this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance()); - return this._sharedLinksApi; - } - - _favoritesApi: FavoritesApi; - get favoritesApi(): FavoritesApi { - this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance()); - return this._favoritesApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - constructor(private apiService: AlfrescoApiService, private logService: LogService) { + private getAsNodePaging(nodes: { list?: any }): NodePaging { + const result = new NodePaging(); + result.list = nodes.list; + return result; } /** @@ -94,77 +46,7 @@ export class CustomResourcesService { * @returns List of nodes for the recently used files */ getRecentFiles(personId: string, pagination: PaginationModel, filters?: string[]): Observable { - const defaultFilter = [ - 'TYPE:"content"', - '-PNAME:"0/wiki"', - '-TYPE:"app:filelink"', - '-TYPE:"cm:thumbnail"', - '-TYPE:"cm:failedThumbnail"', - '-TYPE:"cm:rating"', - '-TYPE:"dl:dataList"', - '-TYPE:"dl:todoList"', - '-TYPE:"dl:issue"', - '-TYPE:"dl:contact"', - '-TYPE:"dl:eventAgenda"', - '-TYPE:"dl:event"', - '-TYPE:"dl:task"', - '-TYPE:"dl:simpletask"', - '-TYPE:"dl:meetingAgenda"', - '-TYPE:"dl:location"', - '-TYPE:"fm:topic"', - '-TYPE:"fm:post"', - '-TYPE:"ia:calendarEvent"', - '-TYPE:"lnk:link"' - ]; - - return new Observable((observer) => { - this.peopleApi.getPerson(personId) - .then((person) => { - const username = person.entry.id; - const filterQueries = [ - { query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` }, - { query: `cm:modifier:${username} OR cm:creator:${username}` }, - { query: defaultFilter.join(' AND ') } - ]; - - if (filters && filters.length > 0) { - filterQueries.push({ - query: filters.join() - }); - } - - const query = new SearchRequest({ - query: { - query: '*', - language: 'afts' - }, - filterQueries, - include: ['path', 'properties', 'allowableOperations'], - sort: [{ - type: 'FIELD', - field: 'cm:modified', - ascending: false - }], - paging: { - maxItems: pagination.maxItems, - skipCount: pagination.skipCount - } - }); - return this.searchApi.search(query) - .then((searchResult) => { - observer.next(searchResult); - observer.complete(); - }, - (err) => { - observer.error(err); - observer.complete(); - }); - }, - (err) => { - observer.error(err); - observer.complete(); - }); - }).pipe(catchError((err) => this.handleError(err))); + return this.contentService.getRecentFiles(personId, pagination, filters).pipe(map(nodes => this.getAsNodePaging(nodes)), catchError((err) => this.handleError(err))); } /** @@ -175,48 +57,7 @@ export class CustomResourcesService { * @returns List of favorite files */ loadFavorites(pagination: PaginationModel, includeFields: string[] = [], where?: string): Observable { - const includeFieldsRequest = this.getIncludesFields(includeFields); - const defaultPredicate = '(EXISTS(target/file) OR EXISTS(target/folder))'; - - const options = { - maxItems: pagination.maxItems, - skipCount: pagination.skipCount, - where: where ? `${where} AND ${defaultPredicate}` : defaultPredicate, - include: includeFieldsRequest - }; - - return new Observable((observer) => { - this.favoritesApi.listFavorites('-me-', options) - .then((result: FavoritePaging) => { - const page: FavoritePaging = { - list: { - entries: result.list.entries - .map(({ entry }: any) => { - const target = entry.target.file || entry.target.folder; - target.properties = { - ...(target.properties || { - 'cm:title': entry.title || target.title, - 'cm:description': entry.description || target.description - }), - ...(entry.properties || {}) - }; - - return { - entry: target - }; - }), - pagination: result.list.pagination - } - }; - - observer.next(page); - observer.complete(); - }, - (err) => { - observer.error(err); - observer.complete(); - }); - }).pipe(catchError((err) => this.handleError(err))); + return this.contentService.loadFavorites(pagination, includeFields, where).pipe(map(nodes => this.getAsNodePaging(nodes)), catchError((err) => this.handleError(err))); } /** @@ -226,38 +67,7 @@ export class CustomResourcesService { * @returns List of sites */ loadMemberSites(pagination: PaginationModel, where?: string): Observable { - const options = { - include: ['properties'], - maxItems: pagination.maxItems, - skipCount: pagination.skipCount, - where - }; - - return new Observable((observer) => { - this.sitesApi.listSiteMembershipsForPerson('-me-', options) - .then((result: SiteRolePaging) => { - const page: SiteMemberPaging = new SiteMemberPaging({ - list: { - entries: result.list.entries - .map(({ entry: { site } }: any) => { - site.allowableOperations = site.allowableOperations ? site.allowableOperations : [this.CREATE_PERMISSION]; - site.name = site.name || site.title; - return { - entry: site - }; - }), - pagination: result.list.pagination - } - }); - - observer.next(page); - observer.complete(); - }, - (err) => { - observer.error(err); - observer.complete(); - }); - }).pipe(catchError((err) => this.handleError(err))); + return this.contentService.loadMemberSites(pagination, where).pipe(catchError((err) => this.handleError(err))); } /** @@ -267,32 +77,7 @@ export class CustomResourcesService { * @returns List of sites */ loadSites(pagination: PaginationModel, where?: string): Observable { - const options = { - include: ['properties', 'aspectNames'], - maxItems: pagination.maxItems, - skipCount: pagination.skipCount, - where - }; - - return new Observable((observer) => { - this.sitesApi - .listSites(options) - .then( - (page) => { - page.list.entries.map( - ({ entry }: any) => { - entry.name = entry.name || entry.title; - return { entry }; - } - ); - observer.next(page); - observer.complete(); - }, - (err) => { - observer.error(err); - observer.complete(); - }); - }).pipe(catchError((err) => this.handleError(err))); + return this.contentService.loadSites(pagination, where).pipe(map(nodes => this.getAsNodePaging(nodes)), catchError((err) => this.handleError(err))); } /** @@ -302,16 +87,7 @@ export class CustomResourcesService { * @returns List of deleted items */ loadTrashcan(pagination: PaginationModel, includeFields: string[] = []): Observable { - const includeFieldsRequest = this.getIncludesFields(includeFields); - - const options = { - include: includeFieldsRequest, - maxItems: pagination.maxItems, - skipCount: pagination.skipCount - }; - - return from(this.trashcanApi.listDeletedNodes(options)) - .pipe(catchError((err) => this.handleError(err))); + return this.contentService.loadTrashcan(pagination, includeFields).pipe(catchError((err) => this.handleError(err))); } @@ -323,17 +99,7 @@ export class CustomResourcesService { * @returns List of shared links */ loadSharedLinks(pagination: PaginationModel, includeFields: string[] = [], where?: string): Observable { - const includeFieldsRequest = this.getIncludesFields(includeFields); - - const options = { - include: includeFieldsRequest, - maxItems: pagination.maxItems, - skipCount: pagination.skipCount, - where - }; - - return from(this.sharedLinksApi.listSharedLinks(options)) - .pipe(catchError((err) => this.handleError(err))); + return this.contentService.loadSharedLinks(pagination, includeFields, where).pipe(catchError((err) => this.handleError(err))); } /** @@ -410,31 +176,12 @@ export class CustomResourcesService { } else if (nodeId) { // cases when nodeId is '-my-', '-root-' or '-shared-' - return from(this.nodesApi.getNode(nodeId) - .then((node) => [node.entry.id])); + return this.contentService.getNode(nodeId).pipe(map((node) => [node.entry.id])); } return of([]); } - /** - * Chooses the correct ID for a node entry. - * @param node Node object - * @param nodeId ID of the node object - * @returns ID value - */ - getIdFromEntry(node: any, nodeId: string): string { - if (nodeId === '-sharedlinks-') { - return node.entry.nodeId; - } else if (nodeId === '-sites-' || nodeId === '-mysites-') { - return node.entry.guid; - } else if (nodeId === '-favorites-') { - return node.entry.targetGuid; - } else { - return node.entry.id; - } - } - /** * Does the well-known alias have a corresponding node ID? * @param nodeId Node to check @@ -444,9 +191,16 @@ export class CustomResourcesService { return this.isCustomSource(nodeId) || this.isSupportedSource(nodeId); } - private getIncludesFields(includeFields: string[]): string[] { - return ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields] - .filter((element, index, array) => index === array.indexOf(element)); + private getIdFromEntry(node: any, nodeId: string): string { + if (nodeId === '-sharedlinks-') { + return node.entry.nodeId; + } else if (nodeId === '-sites-' || nodeId === '-mysites-') { + return node.entry.guid; + } else if (nodeId === '-favorites-') { + return node.entry.targetGuid; + } else { + return node.entry.id; + } } private handleError(error: Response) { diff --git a/lib/content-services/src/lib/document-list/services/document-list.service.ts b/lib/content-services/src/lib/document-list/services/document-list.service.ts index 2e1f9ba7f1..d98c9a420e 100644 --- a/lib/content-services/src/lib/document-list/services/document-list.service.ts +++ b/lib/content-services/src/lib/document-list/services/document-list.service.ts @@ -16,11 +16,11 @@ */ import { - AlfrescoApiService, ContentService, LogService, PaginationModel + ContentService, LogService, PaginationModel } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; -import { NodeEntry, NodePaging, NodesApi } from '@alfresco/js-api'; +import { NodeEntry, NodePaging } from '@alfresco/js-api'; import { DocumentLoaderNode } from '../models/document-folder.model'; import { Observable, from, throwError, forkJoin } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; @@ -34,14 +34,7 @@ export class DocumentListService implements DocumentListLoader { static ROOT_ID = '-root-'; - _nodesApi: NodesApi; - get nodes(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - constructor(private contentService: ContentService, - private apiService: AlfrescoApiService, private logService: LogService, private customResourcesService: CustomResourcesService) { } @@ -52,7 +45,7 @@ export class DocumentListService implements DocumentListLoader { * @returns Empty response when the operation is complete */ deleteNode(nodeId: string): Observable { - return from(this.nodes.deleteNode(nodeId)); + return from(this.contentService.deleteNode(nodeId)); } /** @@ -63,7 +56,7 @@ export class DocumentListService implements DocumentListLoader { * @returns NodeEntry for the copied node */ copyNode(nodeId: string, targetParentId: string): Observable { - return from(this.nodes.copyNode(nodeId, { targetParentId })).pipe( + return from(this.contentService.copyNode(nodeId, { targetParentId })).pipe( catchError((err) => this.handleError(err)) ); } @@ -76,7 +69,7 @@ export class DocumentListService implements DocumentListLoader { * @returns NodeEntry for the moved node */ moveNode(nodeId: string, targetParentId: string): Observable { - return from(this.nodes.moveNode(nodeId, { targetParentId })).pipe( + return from(this.contentService.moveNode(nodeId, { targetParentId })).pipe( catchError((err) => this.handleError(err)) ); } @@ -121,7 +114,7 @@ export class DocumentListService implements DocumentListLoader { } } - return from(this.nodes.listNodeChildren(rootNodeId, params)).pipe( + return from(this.contentService.listNodeChildren(rootNodeId, params)).pipe( catchError((err) => this.handleError(err)) ); } @@ -159,7 +152,7 @@ export class DocumentListService implements DocumentListLoader { include: includeFieldsRequest }; - return from(this.nodes.getNode(nodeId, opts)).pipe( + return this.contentService.getNode(nodeId, opts).pipe( catchError((err) => this.handleError(err)) ); } diff --git a/lib/content-services/src/lib/document-list/services/node-actions.service.ts b/lib/content-services/src/lib/document-list/services/node-actions.service.ts index 0ebd7ec3d5..d03cec86ce 100644 --- a/lib/content-services/src/lib/document-list/services/node-actions.service.ts +++ b/lib/content-services/src/lib/document-list/services/node-actions.service.ts @@ -18,7 +18,7 @@ import { Injectable, Output, EventEmitter } from '@angular/core'; import { Node, NodeEntry } from '@alfresco/js-api'; import { Subject } from 'rxjs'; -import { AlfrescoApiService, ContentService, NodeDownloadDirective, DownloadService } from '@alfresco/adf-core'; +import { ContentService, NodeDownloadDirective, DownloadService } from '@alfresco/adf-core'; import { MatDialog } from '@angular/material/dialog'; import { DocumentListService } from './document-list.service'; @@ -36,14 +36,13 @@ export class NodeActionsService { constructor(private contentDialogService: ContentNodeDialogService, public dialogRef: MatDialog, - public content: ContentService, + public contentService: ContentService, private documentListService?: DocumentListService, - private apiService?: AlfrescoApiService, private dialog?: MatDialog, private downloadService?: DownloadService) {} downloadNode(node: NodeEntry) { - new NodeDownloadDirective(this.apiService, this.downloadService, this.dialog) + new NodeDownloadDirective(this.contentService, this.downloadService, this.dialog) .downloadNode(node); } diff --git a/lib/content-services/src/lib/version-manager/version-list.component.ts b/lib/content-services/src/lib/version-manager/version-list.component.ts index af478bff30..5a8d6abda3 100644 --- a/lib/content-services/src/lib/version-manager/version-list.component.ts +++ b/lib/content-services/src/lib/version-manager/version-list.component.ts @@ -15,9 +15,9 @@ * limitations under the License. */ -import { AlfrescoApiService, ContentService } from '@alfresco/adf-core'; +import { ContentService } from '@alfresco/adf-core'; import { Component, Input, OnChanges, ViewEncapsulation, EventEmitter, Output } from '@angular/core'; -import { VersionsApi, Node, VersionEntry, VersionPaging, NodesApi, NodeEntry, ContentApi } from '@alfresco/js-api'; +import { Node, VersionEntry, VersionPaging, NodeEntry } from '@alfresco/js-api'; import { MatDialog } from '@angular/material/dialog'; import { ConfirmDialogComponent } from '../dialogs/confirm.dialog'; @@ -32,24 +32,6 @@ import { ConfirmDialogComponent } from '../dialogs/confirm.dialog'; }) export class VersionListComponent implements OnChanges { - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.alfrescoApi.getInstance()); - return this._contentApi; - } - - _versionsApi: VersionsApi; - get versionsApi(): VersionsApi { - this._versionsApi = this._versionsApi ?? new VersionsApi(this.alfrescoApi.getInstance()); - return this._versionsApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApi.getInstance()); - return this._nodesApi; - } - versions: VersionEntry[] = []; isLoading = true; @@ -85,8 +67,7 @@ export class VersionListComponent implements OnChanges { @Output() viewVersion: EventEmitter = new EventEmitter(); - constructor(private alfrescoApi: AlfrescoApiService, - private contentService: ContentService, + constructor(private contentService: ContentService, private dialog: MatDialog) { } @@ -104,15 +85,14 @@ export class VersionListComponent implements OnChanges { restore(versionId) { if (this.canUpdate()) { - this.versionsApi + this.contentService .revertVersion(this.node.id, versionId, { majorVersion: true, comment: '' }) .then(() => - this.nodesApi.getNode( + this.contentService.getNode( this.node.id, { include: ['permissions', 'path', 'isFavorite', 'allowableOperations'] } - ) - ) - .then((node) => this.onVersionRestored(node)); + ).subscribe((node) => this.onVersionRestored(node)) + ); } } @@ -122,7 +102,7 @@ export class VersionListComponent implements OnChanges { loadVersionHistory() { this.isLoading = true; - this.versionsApi.listVersionHistory(this.node.id).then((versionPaging: VersionPaging) => { + this.contentService.listVersionHistory(this.node.id).then((versionPaging: VersionPaging) => { this.versions = versionPaging.list.entries; this.isLoading = false; }); @@ -149,7 +129,7 @@ export class VersionListComponent implements OnChanges { dialogRef.afterClosed().subscribe((result) => { if (result === true) { - this.versionsApi + this.contentService .deleteVersion(this.node.id, versionId) .then(() => this.onVersionDeleted(this.node)); } @@ -168,7 +148,7 @@ export class VersionListComponent implements OnChanges { } private getVersionContentUrl(nodeId: string, versionId: string, attachment?: boolean) { - const nodeDownloadUrl = this.contentApi.getContentUrl(nodeId, attachment); + const nodeDownloadUrl = this.contentService.getContentUrl(nodeId, attachment); return nodeDownloadUrl.replace('/content', '/versions/' + versionId + '/content'); } diff --git a/lib/core/core.module.ts b/lib/core/core.module.ts index 3f466dd708..307b7de83e 100644 --- a/lib/core/core.module.ts +++ b/lib/core/core.module.ts @@ -151,13 +151,13 @@ export class CoreModule { { provide: APP_INITIALIZER, useFactory: directionalityConfigFactory, - deps: [ DirectionalityConfigService ], + deps: [DirectionalityConfigService], multi: true }, { provide: APP_INITIALIZER, useFactory: versionCompatibilityFactory, - deps: [ VersionCompatibilityService ], + deps: [VersionCompatibilityService], multi: true } ] diff --git a/lib/core/directives/node-delete.directive.ts b/lib/core/directives/node-delete.directive.ts index d9f5dc9079..810d0a6345 100644 --- a/lib/core/directives/node-delete.directive.ts +++ b/lib/core/directives/node-delete.directive.ts @@ -18,11 +18,11 @@ /* tslint:disable:no-input-rename */ import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output } from '@angular/core'; -import { NodeEntry, Node, DeletedNodeEntity, DeletedNode, TrashcanApi, NodesApi } from '@alfresco/js-api'; +import { NodeEntry, Node, DeletedNodeEntity, DeletedNode } from '@alfresco/js-api'; import { Observable, forkJoin, from, of } from 'rxjs'; -import { AlfrescoApiService } from '../services/alfresco-api.service'; import { TranslationService } from '../services/translation.service'; import { map, catchError, retry } from 'rxjs/operators'; +import { ContentService } from '../services/content.service'; interface ProcessedNodeData { entry: Node | DeletedNode; @@ -62,24 +62,12 @@ export class NodeDeleteDirective implements OnChanges { @Output() delete: EventEmitter = new EventEmitter(); - _trashcanApi: TrashcanApi; - get trashcanApi(): TrashcanApi { - this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.alfrescoApiService.getInstance()); - return this._trashcanApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance()); - return this._nodesApi; - } - @HostListener('click') onClick() { this.process(this.selection); } - constructor(private alfrescoApiService: AlfrescoApiService, + constructor(private contentService: ContentService, private translation: TranslationService, private elementRef: ElementRef) { } @@ -125,9 +113,9 @@ export class NodeDeleteDirective implements OnChanges { let promise: Promise; if (node.entry.hasOwnProperty('archivedAt') && node.entry['archivedAt']) { - promise = this.trashcanApi.deleteDeletedNode(id); + promise = this.contentService.deleteDeletedNode(id); } else { - promise = this.nodesApi.deleteNode(id, { permanent: this.permanent }); + promise = this.contentService.deleteNode(id, { permanent: this.permanent }); } return from(promise).pipe( diff --git a/lib/core/directives/node-download.directive.ts b/lib/core/directives/node-download.directive.ts index e1b81b2241..96676887f6 100755 --- a/lib/core/directives/node-download.directive.ts +++ b/lib/core/directives/node-download.directive.ts @@ -17,10 +17,10 @@ import { Directive, Input, HostListener } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { AlfrescoApiService } from '../services/alfresco-api.service'; import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog'; -import { ContentApi, NodeEntry, VersionEntry } from '@alfresco/js-api'; +import { NodeEntry, VersionEntry } from '@alfresco/js-api'; import { DownloadService } from '../services/download.service'; +import { ContentService } from '../services/content.service'; /** * Directive selectors without adf- prefix will be deprecated on 3.0.0 @@ -31,12 +31,6 @@ import { DownloadService } from '../services/download.service'; }) export class NodeDownloadDirective { - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; - } - /** Nodes to download. */ @Input('adfNodeDownload') nodes: NodeEntry | NodeEntry[]; @@ -51,7 +45,7 @@ export class NodeDownloadDirective { } constructor( - private apiService: AlfrescoApiService, + private contentService: ContentService, private downloadService: DownloadService, private dialog: MatDialog) { } @@ -112,10 +106,10 @@ export class NodeDownloadDirective { let url, fileName; if (this.version) { - url = this.contentApi.getVersionContentUrl(id, this.version.entry.id, true); + url = this.contentService.getVersionContentUrl(id, this.version.entry.id, true); fileName = this.version.entry.name; } else { - url = this.contentApi.getContentUrl(id, true); + url = this.contentService.getContentUrl(id, true); fileName = node.entry.name; } diff --git a/lib/core/services/acs-content.service.ts b/lib/core/services/acs-content.service.ts new file mode 100644 index 0000000000..70850cee6a --- /dev/null +++ b/lib/core/services/acs-content.service.ts @@ -0,0 +1,576 @@ +/*! + * @license + * Copyright 2019 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 { Injectable } from '@angular/core'; +import { + ContentApi, + DeletedNodesPaging, + DiscoveryApi, + DiscoveryEntry, + FavoriteBodyCreate, + FavoriteEntry, + FavoritePaging, + FavoritesApi, + NodeBodyCopy, + NodeBodyCreate, + NodeBodyLock, + NodeBodyMove, + NodeBodyUpdate, + NodeChildAssociationPaging, + NodeEntry, + NodesApi, + PeopleApi, + PersonEntry, + RenditionBodyCreate, + RenditionEntry, + RenditionPaging, + RenditionsApi, + ResultSetPaging, + RevertBody, + SearchApi, + SearchRequest, + SharedLinkEntry, + SharedLinkPaging, + SharedlinksApi, + SiteBody, + SiteEntry, + SiteMemberPaging, + SitePaging, + SiteRolePaging, + SitesApi, + TrashcanApi, + UploadApi, + VersionEntry, + VersionPaging, + VersionsApi +} from '@alfresco/js-api'; +import { Observable, from } from 'rxjs'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { ContentServiceProvider } from './content-provider.service'; +import { PaginationModel } from '../models/pagination.model'; + +@Injectable({ + providedIn: 'root' +}) +export class AcsContentService implements ContentServiceProvider { + + private CREATE_PERMISSION = 'create'; + + _contentApi: ContentApi; + get contentApi(): ContentApi { + this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); + return this._contentApi; + } + + _nodesApi: NodesApi; + get nodesApi(): NodesApi { + this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); + return this._nodesApi; + } + + _versionsApi: VersionsApi; + get versionsApi(): VersionsApi { + this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); + return this._versionsApi; + } + + _trashcanApi: TrashcanApi; + get trashcanApi(): TrashcanApi { + this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance()); + return this._trashcanApi; + } + + _sharedLinksApi: SharedlinksApi; + get sharedLinksApi(): SharedlinksApi { + this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance()); + return this._sharedLinksApi; + } + + _uploadApi: UploadApi; + get uploadApi(): UploadApi { + this._uploadApi = this._uploadApi ?? new UploadApi(this.apiService.getInstance()); + return this._uploadApi; + } + + _renditionsApi: RenditionsApi; + get renditionsApi(): RenditionsApi { + this._renditionsApi = this._renditionsApi ?? new RenditionsApi(this.apiService.getInstance()); + return this._renditionsApi; + } + + _peopleApi: PeopleApi; + get peopleApi(): PeopleApi { + this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance()); + return this._peopleApi; + } + + _sitesApi: SitesApi; + get sitesApi(): SitesApi { + this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance()); + return this._sitesApi; + } + + _searchApi: SearchApi; + get searchApi(): SearchApi { + this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance()); + return this._searchApi; + } + + _favoritesApi: FavoritesApi; + get favoritesApi(): FavoritesApi { + this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance()); + return this._favoritesApi; + } + + _discoveryApi: DiscoveryApi; + get discoveryApi(): DiscoveryApi { + this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.apiService.getInstance()); + return this._discoveryApi; + } + + constructor(public apiService: AlfrescoApiService) { + } + + getNodePrefix() { + return 'alfresco://'; + } + + getContentUrl(node: NodeEntry | string, attachment?: boolean, ticket?: string): string { + if (node) { + let nodeId: string; + + if (typeof node === 'string') { + nodeId = node; + } else if (node.entry) { + nodeId = node.entry.id; + } + + return this.contentApi.getContentUrl(nodeId, attachment, ticket); + } + + return null; + } + + getDocumentThumbnailUrl(nodeId: string, attachment?: boolean, ticket?: string): string { + return this.contentApi.getDocumentThumbnailUrl(nodeId, attachment, ticket); + } + + getVersionContentUrl(nodeId: string, versionId: string, attachment?: boolean, ticket?: string): string { + return this.contentApi.getVersionContentUrl(nodeId, versionId, attachment, ticket); + } + + getSharedLinkContentUrl(linkId: string, attachment?: boolean): string { + return this.contentApi.getSharedLinkContentUrl(linkId, attachment); + } + + getSharedLinkRenditionUrl(sharedId: string, renditionId: string, attachment?: boolean): string { + return this.contentApi.getSharedLinkRenditionUrl(sharedId, renditionId, attachment); + } + + getRenditionUrl(nodeId: string, encoding: string, attachment?: boolean, ticket?: string): string { + return this.contentApi.getRenditionUrl(nodeId, encoding, attachment, ticket); + } + + getVersionRenditionUrl(nodeId: string, versionId: string, encoding: string, attachment?: boolean, ticket?: string): string { + return this.contentApi.getVersionRenditionUrl(nodeId, versionId, encoding, attachment, ticket); + } + + getNodeContent(nodeId: string): Promise { + return this.nodesApi.getNodeContent(nodeId); + } + + getNode(nodeId: string, opts?: any): Promise { + return this.nodesApi.getNode(nodeId, opts); + } + + lockNode(nodeId: string, nodeBodyLock: NodeBodyLock, opts?: any): Promise { + return this.nodesApi.lockNode(nodeId, nodeBodyLock, opts); + } + + unlockNode(nodeId: string, opts?: any): Promise { + return this.nodesApi.unlockNode(nodeId, opts); + } + + deleteNode(nodeId: string, opts?: any): Promise { + return this.nodesApi.deleteNode(nodeId, opts); + } + + copyNode(nodeId: string, nodeBodyCopy: NodeBodyCopy, opts?: any): Promise { + return this.nodesApi.copyNode(nodeId, nodeBodyCopy, opts); + } + + moveNode(nodeId: string, nodeBodyMove: NodeBodyMove, opts?: any): Promise { + return this.nodesApi.moveNode(nodeId, nodeBodyMove, opts); + } + + listNodeChildren(nodeId: string, opts?: any): Promise { + return this.nodesApi.listNodeChildren(nodeId, opts); + } + + createNode(nodeId: string, nodeBodyCreate: NodeBodyCreate, opts?: any, formParams?: any): Promise { + return this.nodesApi.createNode(nodeId, nodeBodyCreate, opts, formParams); + } + + updateNode(nodeId: string, nodeBodyUpdate: NodeBodyUpdate, opts?: any): Promise { + return this.nodesApi.updateNode(nodeId, nodeBodyUpdate, opts); + } + + updateNodeContent(nodeId: string, contentBodyUpdate: string, opts?: any): Promise { + return this.nodesApi.updateNodeContent(nodeId, contentBodyUpdate, opts); + } + + revertVersion(nodeId: string, versionId: string, revertBody: RevertBody, opts?: any): Promise { + return this.versionsApi.revertVersion(nodeId, versionId, revertBody, opts); + } + + deleteVersion(nodeId: string, versionId: string): Promise { + return this.versionsApi.deleteVersion(nodeId, versionId); + } + + listVersionHistory(nodeId: string, opts?: any): Promise { + return this.versionsApi.listVersionHistory(nodeId, opts); + } + + getVersion(nodeId: string, versionId: string): Promise { + return this.versionsApi.getVersion(nodeId, versionId); + } + + listVersionRenditions(nodeId: string, versionId: string, opts?: any): Promise { + return this.versionsApi.listVersionRenditions(nodeId, versionId, opts); + } + + createVersionRendition(nodeId: string, versionId: string, renditionBodyCreate: RenditionBodyCreate): Promise { + return this.versionsApi.createVersionRendition(nodeId, versionId, renditionBodyCreate); + } + + getVersionRendition(nodeId: string, versionId: string, renditionId: string): Promise { + return this.versionsApi.getVersionRendition(nodeId, versionId, renditionId); + } + + getNodeVersions(nodeId: string, opts?: any) { + return from(this.versionsApi.listVersionHistory(nodeId, opts)); + } + + deleteDeletedNode(nodeId: string): Promise { + return this.trashcanApi.deleteDeletedNode(nodeId); + } + + listDeletedNodes(opts?: any): Promise { + return this.trashcanApi.listDeletedNodes(opts); + } + + restoreDeletedNode(nodeId: string, opts?: any): Promise { + return this.trashcanApi.restoreDeletedNode(nodeId, opts); + } + + getSharedLink(sharedId: string, opts?: any): Promise { + return this.sharedLinksApi.getSharedLink(sharedId, opts); + } + + getSharedLinkRendition(sharedId: string, renditionId: string): Promise { + return this.sharedLinksApi.getSharedLinkRendition(sharedId, renditionId); + } + + listSharedLinks(opts?: any): Promise { + return this.sharedLinksApi.listSharedLinks(opts); + } + + deleteSharedLink(sharedId: string): Promise { + return this.sharedLinksApi.deleteSharedLink(sharedId); + } + + uploadFile(fileDefinition: any, relativePath: string, rootFolderId: string, nodeBody: any, opts?: any): Promise { + return this.uploadApi.uploadFile(fileDefinition, relativePath, rootFolderId, nodeBody, opts); + } + + listRenditions(nodeId: string, opts?: any): Promise { + return this.renditionsApi.listRenditions(nodeId, opts); + } + + createRendition(nodeId: string, renditionBodyCreate: RenditionBodyCreate): Promise { + return this.renditionsApi.createRendition(nodeId, renditionBodyCreate); + } + + getRendition(nodeId: string, renditionId: string): Promise { + return this.renditionsApi.getRendition(nodeId, renditionId); + } + + getPerson(personId: string, opts?: any): Promise { + return this.peopleApi.getPerson(personId, opts); + } + + getRepositoryInformation(): Promise { + return this.discoveryApi.getRepositoryInformation(); + } + + listFavorites(personId: string, opts?: any): Promise { + return this.favoritesApi.listFavorites(personId, opts); + } + + createFavorite(personId: string, favoriteBodyCreate: FavoriteBodyCreate, opts?: any): Promise { + return this.favoritesApi.createFavorite(personId, favoriteBodyCreate, opts); + } + + deleteFavorite(personId: string, favoriteId: string): Promise { + return this.favoritesApi.deleteFavorite(personId, favoriteId); + } + + search(request: SearchRequest): Promise { + return this.searchApi.search(request); + } + + deleteSite(siteId?: string, opts?: { permanent?: boolean }): Promise { + return this.sitesApi.deleteSite(siteId, opts); + } + + deleteSiteMembership(siteId: string, personId: string): Promise { + return this.sitesApi.deleteSiteMembership(siteId, personId); + } + + createSite( + siteBody: SiteBody, + opts?: { + fields?: Array; + skipConfiguration?: boolean; + skipAddToFavorites?: boolean; + } + ): Promise { + return this.sitesApi.createSite(siteBody, opts); + } + + getSite(siteId?: string, opts?: { relations?: Array; fields?: Array }): Promise { + return this.sitesApi.getSite(siteId, opts); + } + + updateSite(siteId: string, siteBody: SiteBody): Promise { + return this.sitesApi.updateSite(siteId, siteBody); + } + + getRecentFiles(personId: string, pagination: PaginationModel, filters?: string[]): Observable { + const defaultFilter = [ + 'TYPE:"content"', + '-PNAME:"0/wiki"', + '-TYPE:"app:filelink"', + '-TYPE:"cm:thumbnail"', + '-TYPE:"cm:failedThumbnail"', + '-TYPE:"cm:rating"', + '-TYPE:"dl:dataList"', + '-TYPE:"dl:todoList"', + '-TYPE:"dl:issue"', + '-TYPE:"dl:contact"', + '-TYPE:"dl:eventAgenda"', + '-TYPE:"dl:event"', + '-TYPE:"dl:task"', + '-TYPE:"dl:simpletask"', + '-TYPE:"dl:meetingAgenda"', + '-TYPE:"dl:location"', + '-TYPE:"fm:topic"', + '-TYPE:"fm:post"', + '-TYPE:"ia:calendarEvent"', + '-TYPE:"lnk:link"' + ]; + + return new Observable((observer) => { + this.peopleApi.getPerson(personId) + .then((person) => { + const username = person.entry.id; + const filterQueries = [ + { query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` }, + { query: `cm:modifier:${username} OR cm:creator:${username}` }, + { query: defaultFilter.join(' AND ') } + ]; + + if (filters && filters.length > 0) { + filterQueries.push({ + query: filters.join() + }); + } + + const query = new SearchRequest({ + query: { + query: '*', + language: 'afts' + }, + filterQueries, + include: ['path', 'properties', 'allowableOperations'], + sort: [{ + type: 'FIELD', + field: 'cm:modified', + ascending: false + }], + paging: { + maxItems: pagination.maxItems, + skipCount: pagination.skipCount + } + }); + return this.searchApi.search(query) + .then((searchResult) => { + observer.next(searchResult); + observer.complete(); + }, + (err) => { + observer.error(err); + observer.complete(); + }); + }, + (err) => { + observer.error(err); + observer.complete(); + }); + }); + } + + loadFavorites(pagination: PaginationModel, includeFields: string[] = [], where?: string): Observable { + const includeFieldsRequest = this.getIncludesFields(includeFields); + const defaultPredicate = '(EXISTS(target/file) OR EXISTS(target/folder))'; + + const options = { + maxItems: pagination.maxItems, + skipCount: pagination.skipCount, + where: where ? `${where} AND ${defaultPredicate}` : defaultPredicate, + include: includeFieldsRequest + }; + + return new Observable((observer) => { + this.favoritesApi.listFavorites('-me-', options) + .then((result: FavoritePaging) => { + const page: FavoritePaging = { + list: { + entries: result.list.entries + .map(({ entry }: any) => { + const target = entry.target.file || entry.target.folder; + target.properties = { + ...(target.properties || { + 'cm:title': entry.title || target.title, + 'cm:description': entry.description || target.description + }), + ...(entry.properties || {}) + }; + + return { + entry: target + }; + }), + pagination: result.list.pagination + } + }; + + observer.next(page); + observer.complete(); + }, + (err) => { + observer.error(err); + observer.complete(); + }); + }); + } + + loadMemberSites(pagination: PaginationModel, where?: string): Observable { + const options = { + include: ['properties'], + maxItems: pagination.maxItems, + skipCount: pagination.skipCount, + where + }; + + return new Observable((observer) => { + this.sitesApi.listSiteMembershipsForPerson('-me-', options) + .then((result: SiteRolePaging) => { + const page: SiteMemberPaging = new SiteMemberPaging({ + list: { + entries: result.list.entries + .map(({ entry: { site } }: any) => { + site.allowableOperations = site.allowableOperations ? site.allowableOperations : [this.CREATE_PERMISSION]; + site.name = site.name || site.title; + return { + entry: site + }; + }), + pagination: result.list.pagination + } + }); + + observer.next(page); + observer.complete(); + }, + (err) => { + observer.error(err); + observer.complete(); + }); + }); + } + + loadSites(pagination: PaginationModel, where?: string): Observable { + const options = { + include: ['properties', 'aspectNames'], + maxItems: pagination.maxItems, + skipCount: pagination.skipCount, + where + }; + + return new Observable((observer) => { + this.sitesApi + .listSites(options) + .then( + (page) => { + page.list.entries.map( + ({ entry }: any) => { + entry.name = entry.name || entry.title; + return { entry }; + } + ); + observer.next(page); + observer.complete(); + }, + (err) => { + observer.error(err); + observer.complete(); + }); + }); + } + + loadTrashcan(pagination: PaginationModel, includeFields: string[] = []): Observable { + const includeFieldsRequest = this.getIncludesFields(includeFields); + + const options = { + include: includeFieldsRequest, + maxItems: pagination.maxItems, + skipCount: pagination.skipCount + }; + + return from(this.trashcanApi.listDeletedNodes(options)); + + } + + loadSharedLinks(pagination: PaginationModel, includeFields: string[] = [], where?: string): Observable { + const includeFieldsRequest = this.getIncludesFields(includeFields); + + const options = { + include: includeFieldsRequest, + maxItems: pagination.maxItems, + skipCount: pagination.skipCount, + where + }; + + return from(this.sharedLinksApi.listSharedLinks(options)); + } + + private getIncludesFields(includeFields: string[]): string[] { + return ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields] + .filter((element, index, array) => index === array.indexOf(element)); + } +} diff --git a/lib/core/services/content-provider.service.ts b/lib/core/services/content-provider.service.ts new file mode 100644 index 0000000000..6b3b3e4223 --- /dev/null +++ b/lib/core/services/content-provider.service.ts @@ -0,0 +1,191 @@ +/*! + * @license + * Copyright 2019 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 { + DeletedNodesPaging, + DiscoveryEntry, + FavoriteBodyCreate, + FavoriteEntry, + FavoritePaging, + NodeBodyCopy, + NodeBodyCreate, + NodeBodyLock, + NodeBodyMove, + NodeBodyUpdate, + NodeChildAssociationPaging, + NodeEntry, + PersonEntry, + RenditionBodyCreate, + RenditionEntry, + RenditionPaging, + ResultSetPaging, + RevertBody, + SearchRequest, + SharedLinkEntry, + SharedLinkPaging, + SiteBody, + SiteEntry, + SiteMemberPaging, + SitePaging, + VersionEntry, + VersionPaging +} from '@alfresco/js-api'; +import { InjectionToken, Provider, Type } from '@angular/core'; +import { Observable } from 'rxjs'; +import { PaginationModel } from '../models/pagination.model'; + +export const CONTENT_SERVICES_PROVIDERS = new InjectionToken('content-services-providers'); + +export const DEFAULT_CONTENT_SERVICES_PROVIDER = new InjectionToken('default-content-services-provider'); + +export function registerContentServiceProvider(implementationClass: Type, defaultProvider: boolean): Provider[] { + const providers = [{ + provide: CONTENT_SERVICES_PROVIDERS, + multi: true, + useExisting: implementationClass + }]; + + if (defaultProvider) { + providers.push({ + provide: DEFAULT_CONTENT_SERVICES_PROVIDER, + multi: false, + useExisting: implementationClass + }); + } + + return providers; +} + +export interface ContentServiceProvider { + + getNodePrefix(); + + getContentUrl(node: NodeEntry | string, attachment?: boolean, ticket?: string); + + getDocumentThumbnailUrl(nodeId: string, attachment?: boolean, ticket?: string); + + getVersionContentUrl(nodeId: string, versionId: string, attachment?: boolean, ticket?: string); + + getSharedLinkContentUrl(linkId: string, attachment?: boolean); + + getSharedLinkRenditionUrl(sharedId: string, renditionId: string, attachment?: boolean); + + getRenditionUrl(nodeId: string, encoding: string, attachment?: boolean, ticket?: string); + + getVersionRenditionUrl(nodeId: string, versionId: string, encoding: string, attachment?: boolean, ticket?: string): string; + + getNodeContent(nodeId: string): Promise; + + getNode(nodeId: string, opts?: any): Promise; + + lockNode(nodeId: string, nodeBodyLock: NodeBodyLock, opts?: any): Promise; + + unlockNode(nodeId: string, opts?: any): Promise; + + deleteNode(nodeId: string, opts?: any): Promise; + + copyNode(nodeId: string, nodeBodyCopy: NodeBodyCopy, opts?: any): Promise; + + moveNode(nodeId: string, nodeBodyMove: NodeBodyMove, opts?: any): Promise; + + listNodeChildren(nodeId: string, opts?: any): Promise; + + createNode(nodeId: string, nodeBodyCreate: NodeBodyCreate, opts?: any, formParams?: any): Promise; + + updateNode(nodeId: string, nodeBodyUpdate: NodeBodyUpdate, opts?: any): Promise; + + updateNodeContent(nodeId: string, contentBodyUpdate: string, opts?: any): Promise; + + revertVersion(nodeId: string, versionId: string, revertBody: RevertBody, opts?: any): Promise; + + deleteVersion(nodeId: string, versionId: string): Promise; + + listVersionHistory(nodeId: string, opts?: any): Promise; + + getVersion(nodeId: string, versionId: string): Promise; + + listVersionRenditions(nodeId: string, versionId: string, opts?: any): Promise; + + createVersionRendition(nodeId: string, versionId: string, renditionBodyCreate: RenditionBodyCreate): Promise; + + getVersionRendition(nodeId: string, versionId: string, renditionId: string): Promise; + + getNodeVersions(nodeId: string, opts?: any); + + deleteDeletedNode(nodeId: string): Promise; + + listDeletedNodes(opts?: any): Promise; + + restoreDeletedNode(nodeId: string, opts?: any): Promise; + + getSharedLink(sharedId: string, opts?: any): Promise; + + getSharedLinkRendition(sharedId: string, renditionId: string): Promise; + + listSharedLinks(opts?: any): Promise; + + deleteSharedLink(sharedId: string): Promise; + + uploadFile(fileDefinition: any, relativePath: string, rootFolderId: string, nodeBody: any, opts?: any): Promise; + + listRenditions(nodeId: string, opts?: any): Promise; + + createRendition(nodeId: string, renditionBodyCreate: RenditionBodyCreate): Promise; + + getRendition(nodeId: string, renditionId: string): Promise; + + getPerson(personId: string, opts?: any): Promise; + + getRepositoryInformation(): Promise; + + listFavorites(personId: string, opts?: any): Promise; + + createFavorite(personId: string, favoriteBodyCreate: FavoriteBodyCreate, opts?: any): Promise; + + deleteFavorite(personId: string, favoriteId: string): Promise; + + search(request: SearchRequest): Promise; + + deleteSite(siteId?: string, opts?: { permanent?: boolean }): Promise; + + deleteSiteMembership(siteId: string, personId: string): Promise; + + createSite( + siteBody: SiteBody, + opts?: { + fields?: Array; + skipConfiguration?: boolean; + skipAddToFavorites?: boolean; + } + ): Promise; + + getSite(siteId?: string, opts?: { relations?: Array; fields?: Array }): Promise; + + updateSite(siteId: string, siteBody: SiteBody): Promise; + + getRecentFiles(personId: string, pagination: PaginationModel, filters?: string[]): Observable; + + loadFavorites(pagination: PaginationModel, includeFields: string[], where?: string): Observable ; + + loadMemberSites(pagination: PaginationModel, where?: string): Observable; + + loadSites(pagination: PaginationModel, where?: string): Observable; + + loadTrashcan(pagination: PaginationModel, includeFields: string[]): Observable; + + loadSharedLinks(pagination: PaginationModel, includeFields: string[], where?: string): Observable; +} diff --git a/lib/core/services/content.service.ts b/lib/core/services/content.service.ts index cf8aa641dc..502de8804e 100644 --- a/lib/core/services/content.service.ts +++ b/lib/core/services/content.service.ts @@ -15,47 +15,96 @@ * limitations under the License. */ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; -import { ContentApi, MinimalNode, Node, NodeEntry, NodesApi } from '@alfresco/js-api'; -import { Observable, Subject, from, throwError } from 'rxjs'; +import { + DeletedNodesPaging, + DeletedNodesPagingList, + DiscoveryEntry, + FavoriteBodyCreate, + FavoriteEntry, + FavoritePaging, + FavoritePagingList, + MinimalNode, + Node, + NodeBodyCopy, + NodeBodyCreate, + NodeBodyLock, + NodeBodyMove, + NodeBodyUpdate, + NodeChildAssociationPaging, + NodeEntry, + PersonEntry, + RenditionBodyCreate, + RenditionEntry, + RenditionPaging, + ResultSetPaging, + ResultSetPagingList, + RevertBody, + SearchRequest, + SharedLinkEntry, + SharedLinkPaging, + SharedLinkPagingList, + SiteBody, + SiteEntry, + SiteMemberPaging, + SiteMemberPagingList, + SitePaging, + SitePagingList, + VersionEntry, + VersionPaging +} from '@alfresco/js-api'; +import { Observable, Subject, throwError, forkJoin, from } from 'rxjs'; import { FolderCreatedEvent } from '../events/folder-created.event'; -import { AlfrescoApiService } from './alfresco-api.service'; import { AuthenticationService } from './authentication.service'; import { LogService } from './log.service'; -import { catchError } from 'rxjs/operators'; +import { catchError, map } from 'rxjs/operators'; import { PermissionsEnum } from '../models/permissions.enum'; import { AllowableOperationsEnum } from '../models/allowable-operations.enum'; import { DownloadService } from './download.service'; -import { ThumbnailService } from './thumbnail.service'; - +import { ContentServiceProvider, CONTENT_SERVICES_PROVIDERS, DEFAULT_CONTENT_SERVICES_PROVIDER } from './content-provider.service'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { AcsContentService } from './acs-content.service'; +import { PaginationModel } from '../models/pagination.model'; @Injectable({ providedIn: 'root' }) export class ContentService { + private defaultProvider: ContentServiceProvider; + folderCreated: Subject = new Subject(); folderCreate: Subject = new Subject(); folderEdit: Subject = new Subject(); - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; + constructor( + public authService: AuthenticationService, + private logService: LogService, + private sanitizer: DomSanitizer, + private downloadService: DownloadService, + private apiService: AlfrescoApiService, + @Inject(CONTENT_SERVICES_PROVIDERS) private providers: ContentServiceProvider[] = [], + @Inject(DEFAULT_CONTENT_SERVICES_PROVIDER) private defaultContentServiceProvider: ContentServiceProvider = null) { + switch (providers.length) { + case 0: + this.defaultProvider = new AcsContentService(this.apiService); + this.providers = [this.defaultProvider]; + break; + case 1: + this.defaultProvider = providers[0]; + break; + default: + this.defaultProvider = defaultContentServiceProvider ? this.defaultContentServiceProvider : providers[0]; + break; + } } - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - constructor(public authService: AuthenticationService, - public apiService: AlfrescoApiService, - private logService: LogService, - private sanitizer: DomSanitizer, - private downloadService: DownloadService, - private thumbnailService: ThumbnailService) { + private getProviderFromId(id: string): ContentServiceProvider { + if (this.providers.length > 1) { + return this.providers.find(provider => id.startsWith(provider.getNodePrefix())) || this.defaultProvider; + } else { + return this.defaultProvider; + } } /** @@ -79,63 +128,6 @@ export class ContentService { return this.sanitizer.bypassSecurityTrustUrl(url); } - /** - * @deprecated in 3.2.0, use ThumbnailService instead. - * Gets a thumbnail URL for the given document node. - * @param node Node or Node ID to get URL for. - * @param attachment Toggles whether to retrieve content as an attachment for download - * @param ticket Custom ticket to use for authentication - * @returns URL string - */ - getDocumentThumbnailUrl(node: NodeEntry | string, attachment?: boolean, ticket?: string): string { - return this.thumbnailService.getDocumentThumbnailUrl(node, attachment, ticket); - } - - /** - * Gets a content URL for the given node. - * @param node Node or Node ID to get URL for. - * @param attachment Toggles whether to retrieve content as an attachment for download - * @param ticket Custom ticket to use for authentication - * @returns URL string or `null` - */ - getContentUrl(node: NodeEntry | string, attachment?: boolean, ticket?: string): string { - if (node) { - let nodeId: string; - - if (typeof node === 'string') { - nodeId = node; - } else if (node.entry) { - nodeId = node.entry.id; - } - - return this.contentApi.getContentUrl(nodeId, attachment, ticket); - } - - return null; - } - - /** - * Gets content for the given node. - * @param nodeId ID of the target node - * @returns Content data - */ - getNodeContent(nodeId: string): Observable { - return from(this.nodesApi.getNodeContent(nodeId)) - .pipe( - catchError((err: any) => this.handleError(err)) - ); - } - - /** - * Gets a Node via its node ID. - * @param nodeId ID of the target node - * @param opts Options supported by JS-API - * @returns Details of the folder - */ - getNode(nodeId: string, opts?: any): Observable { - return from(this.nodesApi.getNode(nodeId, opts)); - } - /** * Checks if the user has permission on that node * @param node Node to check permissions @@ -211,4 +203,336 @@ export class ContentService { this.logService.error(error); return throwError(error || 'Server error'); } + + getDocumentThumbnailUrl(nodeId: string, attachment?: boolean, ticket?: string): string { + return this.getProviderFromId(nodeId).getDocumentThumbnailUrl(nodeId, attachment, ticket); + } + + /** + * Gets a content URL for the given node. + * @param node Node or Node ID to get URL for. + * @param attachment Toggles whether to retrieve content as an attachment for download + * @param ticket Custom ticket to use for authentication + * @returns URL string or `null` + */ + getContentUrl(node: NodeEntry | string, attachment?: boolean, ticket?: string): string { + if (node) { + let nodeId: string; + + if (typeof node === 'string') { + nodeId = node; + } else if (node.entry) { + nodeId = node.entry.id; + } + + return this.getProviderFromId(nodeId).getContentUrl(nodeId, attachment, ticket); + } + + return null; + } + + getVersionContentUrl(nodeId: string, versionId: string, attachment?: boolean, ticket?: string): string { + return this.getProviderFromId(nodeId).getVersionContentUrl(nodeId, versionId, attachment, ticket); + } + + getSharedLinkContentUrl(linkId: string, attachment?: boolean): string { + return this.getProviderFromId(linkId).getSharedLinkContentUrl(linkId, attachment); + } + + getSharedLinkRenditionUrl(sharedId: string, renditionId: string, attachment?: boolean): string { + return this.getProviderFromId(sharedId).getSharedLinkRenditionUrl(sharedId, renditionId, attachment); + } + + getRenditionUrl(nodeId: string, encoding: string, attachment?: boolean, ticket?: string): string { + return this.getProviderFromId(nodeId).getRenditionUrl(nodeId, encoding, attachment, ticket); + } + + getVersionRenditionUrl(nodeId: string, versionId: string, encoding: string, attachment?: boolean, ticket?: string): string { + return this.getProviderFromId(nodeId).getVersionRenditionUrl(nodeId, versionId, encoding, attachment, ticket); + } + + /** + * Gets content for the given node. + * @param nodeId ID of the target node + * @returns Content data + */ + getNodeContent(nodeId: string): Observable { + return from(this.getProviderFromId(nodeId).getNodeContent(nodeId)) + .pipe( + catchError((err: any) => this.handleError(err))); + } + + /** + * Gets a Node via its node ID. + * @param nodeId ID of the target node + * @param opts Options supported by JS-API + * @returns Details of the folder + */ + getNode(nodeId: string, opts?: any): Observable { + return from(this.getProviderFromId(nodeId).getNode(nodeId, opts)); + } + + lockNode(nodeId: string, nodeBodyLock: NodeBodyLock, opts?: any): Promise { + return this.getProviderFromId(nodeId).lockNode(nodeId, nodeBodyLock, opts); + } + + unlockNode(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).unlockNode(nodeId, opts); + } + + deleteNode(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).deleteNode(nodeId, opts); + } + + copyNode(nodeId: string, nodeBodyCopy: NodeBodyCopy, opts?: any): Promise { + return this.getProviderFromId(nodeId).copyNode(nodeId, nodeBodyCopy, opts); + } + + moveNode(nodeId: string, nodeBodyMove: NodeBodyMove, opts?: any): Promise { + return this.getProviderFromId(nodeId).moveNode(nodeId, nodeBodyMove, opts); + } + + listNodeChildren(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).listNodeChildren(nodeId, opts); + } + + createNode(nodeId: string, nodeBodyCreate: NodeBodyCreate, opts?: any, formParams?: any): Promise { + return this.getProviderFromId(nodeId).createNode(nodeId, nodeBodyCreate, opts, formParams); + } + + updateNode(nodeId: string, nodeBodyUpdate: NodeBodyUpdate, opts?: any): Promise { + return this.getProviderFromId(nodeId).updateNode(nodeId, nodeBodyUpdate, opts); + } + + updateNodeContent(nodeId: string, contentBodyUpdate: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).updateNodeContent(nodeId, contentBodyUpdate, opts); + } + + revertVersion(nodeId: string, versionId: string, revertBody: RevertBody, opts?: any): Promise { + return this.getProviderFromId(nodeId).revertVersion(nodeId, versionId, revertBody, opts); + } + + deleteVersion(nodeId: string, versionId: string): Promise { + return this.getProviderFromId(nodeId).deleteVersion(nodeId, versionId); + } + + listVersionHistory(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).listVersionHistory(nodeId, opts); + } + + getVersion(nodeId: string, versionId: string): Promise { + return this.getProviderFromId(nodeId).getVersion(nodeId, versionId); + } + + listVersionRenditions(nodeId: string, versionId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).listVersionRenditions(nodeId, versionId, opts); + } + + createVersionRendition(nodeId: string, versionId: string, renditionBodyCreate: RenditionBodyCreate): Promise { + return this.getProviderFromId(nodeId).createVersionRendition(nodeId, versionId, renditionBodyCreate); + } + + getVersionRendition(nodeId: string, versionId: string, renditionId: string): Promise { + return this.getProviderFromId(nodeId).getVersionRendition(nodeId, versionId, renditionId); + } + + deleteDeletedNode(nodeId: string): Promise { + return this.getProviderFromId(nodeId).deleteDeletedNode(nodeId); + } + + listDeletedNodes(opts?: any): Promise { + const deletedNodes: Promise[] = []; + this.providers.map(provider => deletedNodes.push(provider.listDeletedNodes(opts))); + + return Promise.all(deletedNodes).then(nodes => this.mergeDeletedNodesPaging(nodes)); + } + + restoreDeletedNode(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).restoreDeletedNode(nodeId, opts); + } + + getSharedLink(sharedId: string, opts?: any): Promise { + return this.getProviderFromId(sharedId).getSharedLink(sharedId, opts); + } + + getSharedLinkRendition(sharedId: string, renditionId: string): Promise { + return this.getProviderFromId(sharedId).getSharedLinkRendition(sharedId, renditionId); + } + + listSharedLinks(opts?: any): Promise { + const paging: Promise[] = []; + this.providers.map(provider => paging.push(provider.listSharedLinks(opts))); + + return Promise.all(paging).then(nodes => this.mergeSharedLinkPaging(nodes)); + } + + deleteSharedLink(sharedId: string): Promise { + return this.getProviderFromId(sharedId).deleteSharedLink(sharedId); + } + + uploadFile(fileDefinition: any, relativePath: string, rootFolderId: string, nodeBody: any, opts?: any): Promise { + return this.getProviderFromId(rootFolderId).uploadFile(fileDefinition, relativePath, rootFolderId, nodeBody, opts); + } + + listRenditions(nodeId: string, opts?: any): Promise { + return this.getProviderFromId(nodeId).listRenditions(nodeId, opts); + } + + createRendition(nodeId: string, renditionBodyCreate: RenditionBodyCreate): Promise { + return this.getProviderFromId(nodeId).createRendition(nodeId, renditionBodyCreate); + } + + getRendition(nodeId: string, renditionId: string): Promise { + return this.getProviderFromId(nodeId).getRendition(nodeId, renditionId); + } + + getPerson(personId: string, opts?: any): Promise { + return this.defaultProvider.getPerson(personId, opts); + } + + getRepositoryInformation(): Promise { + return this.defaultProvider.getRepositoryInformation(); + } + + listFavorites(personId: string, opts?: any): Promise { + return this.defaultProvider.listFavorites(personId, opts); + } + + createFavorite(personId: string, favoriteBodyCreate: FavoriteBodyCreate, opts?: any): Promise { + return this.defaultProvider.createFavorite(personId, favoriteBodyCreate, opts); + } + + deleteFavorite(personId: string, favoriteId: string): Promise { + return this.getProviderFromId(favoriteId).deleteFavorite(personId, favoriteId); + } + + search(request: SearchRequest): Promise { + const searchResultNodes: Promise[] = []; + this.providers.map(provider => searchResultNodes.push(provider.search(request))); + + return Promise.all(searchResultNodes).then(nodes => this.mergeResultSetPaging(nodes)); + } + + deleteSite(siteId?: string, opts?: { permanent?: boolean }): Promise { + return this.getProviderFromId(siteId).deleteSite(siteId, opts); + } + + leaveSite(siteId?: string, personId?: string): Promise { + return this.getProviderFromId(siteId).deleteSiteMembership(siteId, personId); + } + + createSite( + siteBody: SiteBody, + opts?: { + fields?: Array; + skipConfiguration?: boolean; + skipAddToFavorites?: boolean; + } + ): Promise { + return this.getProviderFromId(siteBody.id).createSite(siteBody, opts); + } + + getSite(siteId?: string, opts?: { relations?: Array; fields?: Array }): Promise { + return this.getProviderFromId(siteId).getSite(siteId, opts); + } + + updateSite(siteId: string, siteBody: SiteBody): Promise { + return this.getProviderFromId(siteId).updateSite(siteId, siteBody); + } + + getRecentFiles(personId: string, pagination: PaginationModel, filters?: string[]): Observable { + const resultSetPaging: Observable[] = []; + this.providers.map(provider => resultSetPaging.push(provider.getRecentFiles(personId, pagination, filters))); + + return forkJoin(resultSetPaging).pipe(map(nodes => this.mergeResultSetPaging(nodes))); + } + + loadFavorites(pagination: PaginationModel, includeFields: string[], where?: string): Observable { + const paging: Observable[] = []; + this.providers.map(provider => paging.push(provider.loadFavorites(pagination, includeFields, where))); + + return forkJoin(paging).pipe(map(nodes => this.mergeFavoritePaging(nodes))); + } + + loadMemberSites(pagination: PaginationModel, where?: string): Observable { + const paging: Observable[] = []; + this.providers.map(provider => paging.push(provider.loadMemberSites(pagination, where))); + + return forkJoin(paging).pipe(map(nodes => this.mergeSiteMemberPaging(nodes))); + } + + loadSites(pagination: PaginationModel, where?: string): Observable { + const paging: Observable[] = []; + this.providers.map(provider => paging.push(provider.loadSites(pagination, where))); + + return forkJoin(paging).pipe(map(nodes => this.mergeSitePaging(nodes))); + } + + loadTrashcan(pagination: PaginationModel, includeFields: string[]): Observable { + const paging: Observable[] = []; + this.providers.map(provider => paging.push(provider.loadTrashcan(pagination, includeFields))); + + return forkJoin(paging).pipe(map(nodes => this.mergeDeletedNodesPaging(nodes))); + } + + loadSharedLinks(pagination: PaginationModel, includeFields: string[], where?: string): Observable { + const paging: Observable[] = []; + this.providers.map(provider => paging.push(provider.loadSharedLinks(pagination, includeFields, where))); + + return forkJoin(paging).pipe(map(nodes => this.mergeSharedLinkPaging(nodes))); + } + + private mergeDeletedNodesPaging(nodes: DeletedNodesPaging[]): DeletedNodesPaging { + const result = new DeletedNodesPaging(); + result.list = new DeletedNodesPagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } + + private mergeResultSetPaging(nodes: ResultSetPaging[]): ResultSetPaging { + const result = new ResultSetPaging(); + result.list = new ResultSetPagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } + + private mergeFavoritePaging(nodes: FavoritePaging[]): FavoritePaging { + const result = new FavoritePaging(); + result.list = new FavoritePagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } + + private mergeSiteMemberPaging(nodes: SiteMemberPaging[]): SiteMemberPaging { + const result = new SiteMemberPaging(); + result.list = new SiteMemberPagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } + + private mergeSitePaging(nodes: SitePaging[]): SitePaging { + const result = new SitePaging(); + result.list = new SitePagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } + + private mergeSharedLinkPaging(nodes: SharedLinkPaging[]): SharedLinkPaging { + const result = new SharedLinkPaging(); + result.list = new SharedLinkPagingList(); + result.list.pagination = nodes[0].list.pagination; + result.list.entries = []; + nodes.map(node => result.list.entries = result.list.entries.concat(node.list.entries)); + return result; + } } diff --git a/lib/core/services/deleted-nodes-api.service.ts b/lib/core/services/deleted-nodes-api.service.ts index 35465c34b2..f139f41283 100644 --- a/lib/core/services/deleted-nodes-api.service.ts +++ b/lib/core/services/deleted-nodes-api.service.ts @@ -18,30 +18,18 @@ import { Injectable } from '@angular/core'; import { Observable, from, of } from 'rxjs'; -import { NodePaging, NodesApi, TrashcanApi } from '@alfresco/js-api'; -import { AlfrescoApiService } from './alfresco-api.service'; +import { NodePaging } from '@alfresco/js-api'; import { UserPreferencesService } from './user-preferences.service'; import { catchError } from 'rxjs/operators'; +import { ContentService } from './content.service'; @Injectable({ providedIn: 'root' }) export class DeletedNodesApiService { - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - _trashcanApi: TrashcanApi; - get trashcanApi(): TrashcanApi { - this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance()); - return this._trashcanApi; - } - constructor( - private apiService: AlfrescoApiService, + private contentService: ContentService, private preferences: UserPreferencesService ) { } @@ -58,7 +46,7 @@ export class DeletedNodesApiService { skipCount: 0 }; const queryOptions = Object.assign(defaultOptions, options); - const promise = this.trashcanApi.listDeletedNodes(queryOptions); + const promise = this.contentService.listDeletedNodes(queryOptions); return from(promise).pipe( catchError((err) => of(err)) diff --git a/lib/core/services/nodes-api.service.ts b/lib/core/services/nodes-api.service.ts index 076a85f3ff..b9ccda4bca 100644 --- a/lib/core/services/nodes-api.service.ts +++ b/lib/core/services/nodes-api.service.ts @@ -16,31 +16,19 @@ */ import { Injectable } from '@angular/core'; -import { MinimalNode, NodeEntry, NodePaging, NodesApi, TrashcanApi } from '@alfresco/js-api'; +import { MinimalNode, NodeEntry, NodePaging } from '@alfresco/js-api'; import { from, Observable, throwError } from 'rxjs'; -import { AlfrescoApiService } from './alfresco-api.service'; import { UserPreferencesService } from './user-preferences.service'; import { catchError, map } from 'rxjs/operators'; import { NodeMetadata } from '../models/node-metadata.model'; +import { ContentService } from './content.service'; @Injectable({ providedIn: 'root' }) export class NodesApiService { - _trashcanApi: TrashcanApi; - get trashcanApi(): TrashcanApi { - this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance()); - return this._trashcanApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - constructor(private apiService: AlfrescoApiService, + constructor(private contentService: ContentService, private preferences: UserPreferencesService) { } @@ -60,7 +48,7 @@ export class NodesApiService { }; const queryOptions = Object.assign(defaults, options); - return from(this.nodesApi.getNode(nodeId, queryOptions)).pipe( + return this.contentService.getNode(nodeId, queryOptions).pipe( map(this.getEntryFromEntity), catchError((err) => throwError(err)) ); @@ -80,7 +68,7 @@ export class NodesApiService { }; const queryOptions = Object.assign(defaults, options); - return from(this.nodesApi.listNodeChildren(nodeId, queryOptions)).pipe( + return from(this.contentService.listNodeChildren(nodeId, queryOptions)).pipe( catchError((err) => throwError(err)) ); } @@ -93,7 +81,7 @@ export class NodesApiService { * @returns Details of the new node */ createNode(parentNodeId: string, nodeBody: any, options: any = {}): Observable { - return from(this.nodesApi.createNode(parentNodeId, nodeBody, options)).pipe( + return from(this.contentService.createNode(parentNodeId, nodeBody, options)).pipe( map(this.getEntryFromEntity), catchError((err) => throwError(err)) ); @@ -124,7 +112,7 @@ export class NodesApiService { }; const queryOptions = Object.assign(defaults, options); - return from(this.nodesApi.updateNode(nodeId, nodeBody, queryOptions)).pipe( + return from(this.contentService.updateNode(nodeId, nodeBody, queryOptions)).pipe( map(this.getEntryFromEntity), catchError((err) => throwError(err)) ); @@ -137,7 +125,7 @@ export class NodesApiService { * @returns Empty result that notifies when the deletion is complete */ deleteNode(nodeId: string, options: any = {}): Observable { - return from(this.nodesApi.deleteNode(nodeId, options)).pipe( + return from(this.contentService.deleteNode(nodeId, options)).pipe( catchError((err) => throwError(err)) ); } @@ -148,7 +136,7 @@ export class NodesApiService { * @returns Details of the restored node */ restoreNode(nodeId: string): Observable { - return from(this.trashcanApi.restoreDeletedNode(nodeId)).pipe( + return from(this.contentService.restoreDeletedNode(nodeId)).pipe( map(this.getEntryFromEntity), catchError((err) => throwError(err)) ); @@ -160,7 +148,7 @@ export class NodesApiService { * @returns Node metadata */ public getNodeMetadata(nodeId: string): Observable { - return from(this.nodesApi.getNode(nodeId)) + return this.contentService.getNode(nodeId) .pipe(map(this.cleanMetadataFromSemicolon)); } @@ -199,7 +187,7 @@ export class NodesApiService { properties: properties, relativePath: path }; - return from(this.nodesApi.createNode('-root-', body, {})); + return from(this.contentService.createNode('-root-', body, {})); } private generateUuid() { diff --git a/lib/core/services/public-api.ts b/lib/core/services/public-api.ts index dd00320236..6d52b7f0d7 100644 --- a/lib/core/services/public-api.ts +++ b/lib/core/services/public-api.ts @@ -65,3 +65,5 @@ export * from './version-compatibility.service'; export * from './auth-bearer.interceptor'; export * from './oauth2.service'; export * from './language.service'; +export * from './acs-content.service'; +export * from './content-provider.service'; diff --git a/lib/core/services/renditions.service.ts b/lib/core/services/renditions.service.ts index c16b27be99..a8861427f7 100644 --- a/lib/core/services/renditions.service.ts +++ b/lib/core/services/renditions.service.ts @@ -16,29 +16,17 @@ */ import { Injectable } from '@angular/core'; -import { RenditionEntry, RenditionPaging, RenditionsApi, ContentApi } from '@alfresco/js-api'; +import { RenditionEntry, RenditionPaging } from '@alfresco/js-api'; import { Observable, from, interval, empty } from 'rxjs'; -import { AlfrescoApiService } from './alfresco-api.service'; import { concatMap, switchMap, takeWhile, map } from 'rxjs/operators'; +import { ContentService } from './content.service'; @Injectable({ providedIn: 'root' }) export class RenditionsService { - _renditionsApi: RenditionsApi; - get renditionsApi(): RenditionsApi { - this._renditionsApi = this._renditionsApi ?? new RenditionsApi(this.apiService.getInstance()); - return this._renditionsApi; - } - - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; - } - - constructor(private apiService: AlfrescoApiService) { + constructor(private contentService: ContentService) { } /** @@ -47,7 +35,7 @@ export class RenditionsService { * @returns Information object for the rendition */ getAvailableRenditionForNode(nodeId: string): Observable { - return from(this.renditionsApi.listRenditions(nodeId)).pipe( + return from(this.contentService.listRenditions(nodeId)).pipe( map((availableRenditions: RenditionPaging) => { const renditionsAvailable: RenditionEntry[] = availableRenditions.list.entries.filter( (rendition) => (rendition.entry.id === 'pdf' || rendition.entry.id === 'imgpreview')); @@ -65,7 +53,7 @@ export class RenditionsService { return this.getAvailableRenditionForNode(nodeId).pipe( map((rendition: RenditionEntry) => { if (rendition.entry.status !== 'CREATED') { - return from(this.renditionsApi.createRendition(nodeId, { id: rendition.entry.id })); + return from(this.contentService.createRendition(nodeId, { id: rendition.entry.id })); } else { return empty(); } @@ -126,7 +114,7 @@ export class RenditionsService { * @returns URL string */ getRenditionUrl(nodeId: string, encoding: string): string { - return this.contentApi.getRenditionUrl(nodeId, encoding); + return this.contentService.getRenditionUrl(nodeId, encoding); } /** @@ -136,7 +124,7 @@ export class RenditionsService { * @returns Information object about the rendition */ getRendition(nodeId: string, encoding: string): Observable { - return from(this.renditionsApi.getRendition(nodeId, encoding)); + return from(this.contentService.getRendition(nodeId, encoding)); } /** @@ -145,7 +133,7 @@ export class RenditionsService { * @returns Paged list of rendition details */ getRenditionsListByNodeId(nodeId: string): Observable { - return from(this.renditionsApi.listRenditions(nodeId)); + return from(this.contentService.listRenditions(nodeId)); } /** @@ -155,7 +143,7 @@ export class RenditionsService { * @returns Null response to indicate completion */ createRendition(nodeId: string, encoding: string): Observable<{}> { - return from(this.renditionsApi.createRendition(nodeId, { id: encoding })); + return from(this.contentService.createRendition(nodeId, { id: encoding })); } /** diff --git a/lib/core/services/thumbnail.service.ts b/lib/core/services/thumbnail.service.ts index 040441c44b..43e5a8586f 100644 --- a/lib/core/services/thumbnail.service.ts +++ b/lib/core/services/thumbnail.service.ts @@ -19,8 +19,8 @@ import { Injectable } from '@angular/core'; import { MatIconRegistry } from '@angular/material/icon'; import { DomSanitizer } from '@angular/platform-browser'; -import { AlfrescoApiService } from './alfresco-api.service'; -import { ContentApi, NodeEntry } from '@alfresco/js-api'; +import { NodeEntry } from '@alfresco/js-api'; +import { ContentService } from './content.service'; @Injectable({ providedIn: 'root' @@ -164,13 +164,7 @@ export class ThumbnailService { 'task': './assets/images/task.svg' }; - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; - } - - constructor(protected apiService: AlfrescoApiService, matIconRegistry: MatIconRegistry, sanitizer: DomSanitizer) { + constructor(private contentService: ContentService, matIconRegistry: MatIconRegistry, sanitizer: DomSanitizer) { Object.keys(this.mimeTypeIcons).forEach((key) => { const url = sanitizer.bypassSecurityTrustResourceUrl(this.mimeTypeIcons[key]); @@ -198,7 +192,7 @@ export class ThumbnailService { nodeId = node.entry.id; } - resultUrl = this.contentApi.getDocumentThumbnailUrl(nodeId, attachment, ticket); + resultUrl = this.contentService.getDocumentThumbnailUrl(nodeId, attachment, ticket); } return resultUrl || this.DEFAULT_ICON; diff --git a/lib/core/services/upload.service.ts b/lib/core/services/upload.service.ts index 699c974c21..8709681eee 100644 --- a/lib/core/services/upload.service.ts +++ b/lib/core/services/upload.service.ts @@ -26,10 +26,9 @@ import { FileUploadEvent } from '../events/file.event'; import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.model'; -import { AlfrescoApiService } from './alfresco-api.service'; import { DiscoveryApiService } from './discovery-api.service'; import { filter } from 'rxjs/operators'; -import { NodesApi, UploadApi, VersionsApi } from '@alfresco/js-api'; +import { ContentService } from './content.service'; const MIN_CANCELLABLE_FILE_SIZE = 1000000; const MAX_CANCELLABLE_FILE_PERCENTAGE = 50; @@ -63,26 +62,8 @@ export class UploadService { fileUploadDeleted: Subject = new Subject(); fileDeleted: Subject = new Subject(); - _uploadApi: UploadApi; - get uploadApi(): UploadApi { - this._uploadApi = this._uploadApi ?? new UploadApi(this.apiService.getInstance()); - return this._uploadApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - _versionsApi: VersionsApi; - get versionsApi(): VersionsApi { - this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); - return this._versionsApi; - } - constructor( - protected apiService: AlfrescoApiService, + private contentService: ContentService, private appConfigService: AppConfigService, private discoveryApiService: DiscoveryApiService) { @@ -260,9 +241,9 @@ export class UploadService { } if (file.id) { - return this.nodesApi.updateNodeContent(file.id, file.file, opts); + return this.contentService.updateNodeContent(file.id, file.file, opts); } else { - return this.uploadApi.uploadFile( + return this.contentService.uploadFile( file.file, file.options.path, file.options.parentId, @@ -422,12 +403,12 @@ export class UploadService { } private deleteAbortedNode(nodeId: string) { - this.nodesApi.deleteNode(nodeId, { permanent: true }) + this.contentService.deleteNode(nodeId, { permanent: true }) .then(() => (this.abortedFile = undefined)); } private deleteAbortedNodeVersion(nodeId: string, versionId: string) { - this.versionsApi.deleteVersion(nodeId, versionId) + this.contentService.deleteVersion(nodeId, versionId) .then(() => (this.abortedFile = undefined)); } diff --git a/lib/core/viewer/components/viewer.component.ts b/lib/core/viewer/components/viewer.component.ts index 26d3fb60c8..c2af928e5f 100644 --- a/lib/core/viewer/components/viewer.component.ts +++ b/lib/core/viewer/components/viewer.component.ts @@ -26,8 +26,7 @@ import { Version, RenditionEntry, NodeEntry, - VersionEntry, - SharedlinksApi, VersionsApi, NodesApi, ContentApi + VersionEntry } from '@alfresco/js-api'; import { BaseEvent } from '../../events'; import { AlfrescoApiService } from '../../services/alfresco-api.service'; @@ -257,38 +256,15 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { private shouldCloseViewer = true; private keyDown$ = fromEvent(document, 'keydown'); - _sharedLinksApi: SharedlinksApi; - get sharedLinksApi(): SharedlinksApi { - this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance()); - return this._sharedLinksApi; - } - - _versionsApi: VersionsApi; - get versionsApi(): VersionsApi { - this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); - return this._versionsApi; - } - - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; - } - - constructor(private apiService: AlfrescoApiService, - private viewUtilService: ViewUtilService, - private logService: LogService, - private extensionService: AppExtensionService, - private contentService: ContentService, - private uploadService: UploadService, - private el: ElementRef, - public dialog: MatDialog) { + constructor( + private apiService: AlfrescoApiService, + private viewUtilService: ViewUtilService, + private logService: LogService, + private extensionService: AppExtensionService, + private contentService: ContentService, + private uploadService: UploadService, + private el: ElementRef, + public dialog: MatDialog) { viewUtilService.maxRetries = this.maxRetries; } @@ -371,7 +347,7 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { private setupSharedLink() { this.allowGoBack = false; - this.sharedLinksApi.getSharedLink(this.sharedLinkId).then( + this.contentService.getSharedLink(this.sharedLinkId).then( (sharedLinkEntry: SharedLinkEntry) => { this.setUpSharedLinkFile(sharedLinkEntry); this.isLoading = false; @@ -384,11 +360,11 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { } private setupNode() { - this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] }).then( + this.contentService.getNode(this.nodeId, { include: ['allowableOperations'] }).subscribe( (node: NodeEntry) => { this.nodeEntry = node; if (this.versionId) { - this.versionsApi.getVersion(this.nodeId, this.versionId).then( + this.contentService.getVersion(this.nodeId, this.versionId).then( (version: VersionEntry) => { this.versionEntry = version; this.setUpNodeFile(node.entry, version.entry).then(() => { @@ -454,8 +430,8 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { const currentFileVersion = this.nodeEntry?.entry?.properties && this.nodeEntry.entry.properties['cm:versionLabel'] ? encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel']) : encodeURI('1.0'); - this.urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) : - this.contentApi.getContentUrl(this.nodeId); + this.urlFileContent = versionData ? this.contentService.getVersionContentUrl(this.nodeId, versionData.id) : + this.contentService.getContentUrl(this.nodeId); this.urlFileContent = this.cacheBusterNumber ? this.urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber : this.urlFileContent + '&' + currentFileVersion; @@ -490,7 +466,7 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { this.extension = this.getFileExtension(details.entry.name); this.fileName = details.entry.name; - this.urlFileContent = this.contentApi.getSharedLinkContentUrl(this.sharedLinkId, false); + this.urlFileContent = this.contentService.getSharedLinkContentUrl(this.sharedLinkId, false); this.viewerType = this.getViewerTypeByMimeType(this.mimeType); if (this.viewerType === 'unknown') { @@ -507,8 +483,8 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { toggleSidebar() { this.showRightSidebar = !this.showRightSidebar; if (this.showRightSidebar && this.nodeId) { - this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] }) - .then((nodeEntry: NodeEntry) => { + this.contentService.getNode(this.nodeId, { include: ['allowableOperations'] }) + .subscribe((nodeEntry: NodeEntry) => { this.sidebarRightTemplateContext.node = nodeEntry.entry; }); } @@ -517,8 +493,8 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { toggleLeftSidebar() { this.showLeftSidebar = !this.showLeftSidebar; if (this.showRightSidebar && this.nodeId) { - this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] }) - .then((nodeEntry: NodeEntry) => { + this.contentService.getNode(this.nodeId, { include: ['allowableOperations'] }) + .subscribe((nodeEntry: NodeEntry) => { this.sidebarLeftTemplateContext.node = nodeEntry.entry; }); } @@ -702,18 +678,18 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy { private async displaySharedLinkRendition(sharedId: string) { try { - const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf'); + const rendition: RenditionEntry = await this.contentService.getSharedLinkRendition(sharedId, 'pdf'); if (rendition.entry.status.toString() === 'CREATED') { this.viewerType = 'pdf'; - this.urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf'); + this.urlFileContent = this.contentService.getSharedLinkRenditionUrl(sharedId, 'pdf'); } } catch (error) { this.logService.error(error); try { - const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview'); + const rendition: RenditionEntry = await this.contentService.getSharedLinkRendition(sharedId, 'imgpreview'); if (rendition.entry.status.toString() === 'CREATED') { this.viewerType = 'image'; - this.urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview'); + this.urlFileContent = this.contentService.getSharedLinkRenditionUrl(sharedId, 'imgpreview'); } } catch (error) { this.logService.error(error); diff --git a/lib/core/viewer/services/view-util.service.ts b/lib/core/viewer/services/view-util.service.ts index dd032c83c0..13286f8d6c 100644 --- a/lib/core/viewer/services/view-util.service.ts +++ b/lib/core/viewer/services/view-util.service.ts @@ -16,12 +16,12 @@ */ import { Injectable } from '@angular/core'; -import { ContentApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api'; -import { AlfrescoApiService } from '../../services/alfresco-api.service'; +import { RenditionEntry, RenditionPaging } from '@alfresco/js-api'; import { LogService } from '../../services/log.service'; import { Subject } from 'rxjs'; import { Track } from '../models/viewer.model'; import { TranslationService } from '../../services/translation.service'; +import { ContentService } from '../../services/content.service'; @Injectable({ providedIn: 'root' @@ -74,25 +74,7 @@ export class ViewUtilService { viewerTypeChange: Subject = new Subject(); urlFileContentChange: Subject = new Subject(); - _renditionsApi: RenditionsApi; - get renditionsApi(): RenditionsApi { - this._renditionsApi = this._renditionsApi ?? new RenditionsApi(this.apiService.getInstance()); - return this._renditionsApi; - } - - _contentApi: ContentApi; - get contentApi(): ContentApi { - this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); - return this._contentApi; - } - - _versionsApi: VersionsApi; - get versionsApi(): VersionsApi { - this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); - return this._versionsApi; - } - - constructor(private apiService: AlfrescoApiService, + constructor(private contentService: ContentService, private logService: LogService, private translateService: TranslationService) { } @@ -147,12 +129,12 @@ export class ViewUtilService { getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string { return (renditionExists && type !== ViewUtilService.ContentGroup.IMAGE) ? - this.contentApi.getRenditionUrl(nodeId, ViewUtilService.ContentGroup.PDF) : - this.contentApi.getContentUrl(nodeId, false); + this.contentService.getRenditionUrl(nodeId, ViewUtilService.ContentGroup.PDF) : + this.contentService.getContentUrl(nodeId, false); } private async waitRendition(nodeId: string, renditionId: string, retries: number): Promise { - const rendition = await this.renditionsApi.getRendition(nodeId, renditionId); + const rendition = await this.contentService.getRendition(nodeId, renditionId); if (this.maxRetries < retries) { const status = rendition.entry.status.toString(); @@ -188,7 +170,7 @@ export class ViewUtilService { } async getRendition(nodeId: string, renditionId: string): Promise { - const renditionPaging: RenditionPaging = await this.renditionsApi.listRenditions(nodeId); + const renditionPaging: RenditionPaging = await this.contentService.listRenditions(nodeId); let rendition: RenditionEntry = renditionPaging.list.entries.find((renditionEntry: RenditionEntry) => renditionEntry.entry.id.toLowerCase() === renditionId); if (rendition) { @@ -196,7 +178,7 @@ export class ViewUtilService { if (status === 'NOT_CREATED') { try { - await this.renditionsApi.createRendition(nodeId, { id: renditionId }); + await this.contentService.createRendition(nodeId, { id: renditionId }); rendition = await this.waitRendition(nodeId, renditionId, 0); } catch (err) { this.logService.error(err); @@ -219,8 +201,8 @@ export class ViewUtilService { this.viewerTypeChange.next('image'); } - const urlFileContent = versionId ? this.contentApi.getVersionRenditionUrl(nodeId, versionId, renditionId) : - this.contentApi.getRenditionUrl(nodeId, renditionId); + const urlFileContent = versionId ? this.contentService.getVersionRenditionUrl(nodeId, versionId, renditionId) : + this.contentService.getRenditionUrl(nodeId, renditionId); this.urlFileContentChange.next(urlFileContent); } } catch (err) { @@ -231,8 +213,8 @@ export class ViewUtilService { private async resolveNodeRendition(nodeId: string, renditionId: string, versionId?: string): Promise { renditionId = renditionId.toLowerCase(); - const supportedRendition: RenditionPaging = versionId ? await this.versionsApi.listVersionRenditions(nodeId, versionId) : - await this.renditionsApi.listRenditions(nodeId); + const supportedRendition: RenditionPaging = versionId ? await this.contentService.listVersionRenditions(nodeId, versionId) : + await this.contentService.listRenditions(nodeId); let rendition: RenditionEntry = supportedRendition.list.entries.find((renditionEntry: RenditionEntry) => renditionEntry.entry.id.toLowerCase() === renditionId); if (!rendition) { @@ -246,11 +228,11 @@ export class ViewUtilService { if (status === 'NOT_CREATED') { try { if (versionId) { - await this.versionsApi.createVersionRendition(nodeId, versionId, { id: renditionId }).then(() => { + await this.contentService.createVersionRendition(nodeId, versionId, { id: renditionId }).then(() => { this.viewerTypeChange.next('in_creation'); }); } else { - await this.renditionsApi.createRendition(nodeId, { id: renditionId }).then(() => { + await this.contentService.createRendition(nodeId, { id: renditionId }).then(() => { this.viewerTypeChange.next('in_creation'); }); } @@ -277,7 +259,7 @@ export class ViewUtilService { currentRetry++; if (this.maxRetries >= currentRetry) { if (versionId) { - this.versionsApi.getVersionRendition(nodeId, versionId, renditionId).then((rendition: RenditionEntry) => { + this.contentService.getVersionRendition(nodeId, versionId, renditionId).then((rendition: RenditionEntry) => { const status: string = rendition.entry.status.toString(); if (status === 'CREATED') { @@ -289,7 +271,7 @@ export class ViewUtilService { return reject(); }); } else { - this.renditionsApi.getRendition(nodeId, renditionId).then((rendition: RenditionEntry) => { + this.contentService.getRendition(nodeId, renditionId).then((rendition: RenditionEntry) => { const status: string = rendition.entry.status.toString(); if (status === 'CREATED') { @@ -316,8 +298,8 @@ export class ViewUtilService { this.viewerTypeChange.next('image'); } - const urlFileContent = versionId ? this.contentApi.getVersionRenditionUrl(nodeId, versionId, renditionId) : - this.contentApi.getRenditionUrl(nodeId, renditionId); + const urlFileContent = versionId ? this.contentService.getVersionRenditionUrl(nodeId, versionId, renditionId) : + this.contentService.getRenditionUrl(nodeId, renditionId); this.urlFileContentChange.next(urlFileContent); } @@ -328,7 +310,7 @@ export class ViewUtilService { if (value) { tracks.push({ kind: 'subtitles', - src: this.contentApi.getRenditionUrl(nodeId, ViewUtilService.SUBTITLES_RENDITION_NAME), + src: this.contentService.getRenditionUrl(nodeId, ViewUtilService.SUBTITLES_RENDITION_NAME), label: this.translateService.instant('ADF_VIEWER.SUBTITLES') }); } @@ -342,7 +324,7 @@ export class ViewUtilService { } private async isRenditionAvailable(nodeId: string, renditionId: string): Promise { - const renditionPaging: RenditionPaging = await this.renditionsApi.listRenditions(nodeId); + const renditionPaging: RenditionPaging = await this.contentService.listRenditions(nodeId); const rendition: RenditionEntry = renditionPaging.list.entries.find((renditionEntry: RenditionEntry) => renditionEntry.entry.id.toLowerCase() === renditionId); return rendition?.entry?.status?.toString() === 'CREATED' || false; diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts index bc93acd1c2..9e1e4a1157 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts @@ -26,10 +26,10 @@ import { FormValues, ContentLinkModel, AppConfigService, - AlfrescoApiService, - UploadWidgetContentLinkModel + UploadWidgetContentLinkModel, + ContentService } from '@alfresco/adf-core'; -import { Node, NodesApi, RelatedContentRepresentation } from '@alfresco/js-api'; +import { Node, RelatedContentRepresentation } from '@alfresco/js-api'; import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service'; import { ProcessCloudContentService } from '../../../services/process-cloud-content.service'; import { UploadCloudWidgetComponent } from './upload-cloud.widget'; @@ -67,12 +67,6 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i rootNodeId = AttachFileCloudWidgetComponent.ALIAS_USER_FOLDER; selectedNode: Node; - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - constructor( formService: FormService, logger: LogService, @@ -81,7 +75,7 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i notificationService: NotificationService, private contentNodeSelectorService: ContentCloudNodeSelectorService, private appConfigService: AppConfigService, - private apiService: AlfrescoApiService, + private contentService: ContentService, private contentNodeSelectorPanelService: ContentNodeSelectorPanelService ) { super(formService, thumbnails, processCloudContentService, notificationService, logger); @@ -228,7 +222,7 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i contentModelFormFileHandler(file?: any) { if (file?.id && this.isRetrieveMetadataOptionEnabled()) { const values: FormValues = {}; - this.nodesApi.getNode(file.id).then(acsNode => { + this.contentService.getNode(file.id).subscribe(acsNode => { const metadata = acsNode?.entry?.properties; if (metadata) { const keys = Object.keys(metadata); diff --git a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts index 8f43a9771a..388e5e99b5 100644 --- a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts @@ -16,14 +16,14 @@ */ import { Injectable } from '@angular/core'; -import { AlfrescoApiService, NotificationService } from '@alfresco/adf-core'; +import { ContentService, NotificationService } from '@alfresco/adf-core'; import { MatDialog } from '@angular/material/dialog'; import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData, NodeAction } from '@alfresco/adf-content-services'; -import { Node, NodesApi } from '@alfresco/js-api'; +import { Node } from '@alfresco/js-api'; import { Observable, Subject, throwError } from 'rxjs'; @Injectable({ @@ -31,16 +31,10 @@ import { Observable, Subject, throwError } from 'rxjs'; }) export class ContentCloudNodeSelectorService { - _nodesApi: NodesApi; - get nodesApi(): NodesApi { - this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); - return this._nodesApi; - } - sourceNodeNotFound = false; constructor( - private apiService: AlfrescoApiService, + private contentService: ContentService, private notificationService: NotificationService, private dialog: MatDialog) { } @@ -65,8 +59,9 @@ export class ContentCloudNodeSelectorService { } async fetchNodeIdFromRelativePath(alias: string, opts: { relativePath: string }): Promise { - const relativePathNodeEntry: any = await this.nodesApi + const relativePathNodeEntry: any = await this.contentService .getNode(alias, opts) + .toPromise() .catch((err) => { this.sourceNodeNotFound = true; return this.handleError(err); @@ -75,8 +70,9 @@ export class ContentCloudNodeSelectorService { } async fetchAliasNodeId(alias: string): Promise { - const aliasNodeEntry: any = await this.nodesApi + const aliasNodeEntry: any = await this.contentService .getNode(alias) + .toPromise() .catch((err) => this.handleError(err)); return aliasNodeEntry?.entry?.id; } diff --git a/lib/process-services/src/lib/task-list/services/process-upload.service.ts b/lib/process-services/src/lib/task-list/services/process-upload.service.ts index e8795428c2..5768f0a897 100644 --- a/lib/process-services/src/lib/task-list/services/process-upload.service.ts +++ b/lib/process-services/src/lib/task-list/services/process-upload.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { AlfrescoApiService, AppConfigService, DiscoveryApiService, UploadService } from '@alfresco/adf-core'; +import { AlfrescoApiService, AppConfigService, ContentService, DiscoveryApiService, UploadService } from '@alfresco/adf-core'; import { ActivitiContentApi } from '@alfresco/js-api'; import { Injectable } from '@angular/core'; import { throwError } from 'rxjs'; @@ -31,8 +31,13 @@ export class ProcessUploadService extends UploadService { return this._contentApi; } - constructor(protected apiService: AlfrescoApiService, appConfigService: AppConfigService, discoveryApiService: DiscoveryApiService) { - super(apiService, appConfigService, discoveryApiService); + constructor( + contentService: ContentService, + protected apiService: AlfrescoApiService, + appConfigService: AppConfigService, + discoveryApiService: DiscoveryApiService + ) { + super(contentService, appConfigService, discoveryApiService); } getUploadPromise(file: any): any { diff --git a/lib/process-services/src/lib/task-list/services/task-upload.service.ts b/lib/process-services/src/lib/task-list/services/task-upload.service.ts index 8ef0e50b4a..f548b57488 100644 --- a/lib/process-services/src/lib/task-list/services/task-upload.service.ts +++ b/lib/process-services/src/lib/task-list/services/task-upload.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { AlfrescoApiService, AppConfigService, DiscoveryApiService, UploadService } from '@alfresco/adf-core'; +import { AlfrescoApiService, AppConfigService, ContentService, DiscoveryApiService, UploadService } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; import { throwError } from 'rxjs'; import { ActivitiContentApi } from '@alfresco/js-api'; @@ -31,8 +31,13 @@ export class TaskUploadService extends UploadService { return this._contentApi; } - constructor(protected apiService: AlfrescoApiService, appConfigService: AppConfigService, discoveryApiService: DiscoveryApiService) { - super(apiService, appConfigService, discoveryApiService); + constructor( + contentService: ContentService, + protected apiService: AlfrescoApiService, + appConfigService: AppConfigService, + discoveryApiService: DiscoveryApiService + ) { + super(contentService, appConfigService, discoveryApiService); } getUploadPromise(file: any): any {