diff --git a/ng2-components/ng2-alfresco-core/index.ts b/ng2-components/ng2-alfresco-core/index.ts index 25dcfce0ea..d81dccee55 100644 --- a/ng2-components/ng2-alfresco-core/index.ts +++ b/ng2-components/ng2-alfresco-core/index.ts @@ -51,6 +51,14 @@ import { TranslationService } from './src/services/translation.service'; import { UploadService } from './src/services/upload.service'; import { UserPreferencesService } from './src/services/user-preferences.service'; +import { DeletedNodesApiService } from './src/services/deleted-nodes-api.service'; +import { FavoritesApiService } from './src/services/favorites-api.service'; +import { NodesApiService } from './src/services/nodes-api.service'; +import { PeopleApiService } from './src/services/people-api.service'; +import { SearchApiService } from './src/services/search-api.service'; +import { SharedLinksApiService } from './src/services/shared-links-api.service'; +import { SitesApiService } from './src/services/sites-api.service'; + export { ContentService } from './src/services/content.service'; export { StorageService } from './src/services/storage.service'; export { CookieService } from './src/services/cookie.service'; @@ -76,6 +84,14 @@ export { UpdateNotification } from './src/services/card-view-update.service'; export { AppConfigModule } from './src/services/app-config.service'; export { UserPreferencesService } from './src/services/user-preferences.service'; +export { DeletedNodesApiService } from './src/services/deleted-nodes-api.service'; +export { FavoritesApiService } from './src/services/favorites-api.service'; +export { NodesApiService } from './src/services/nodes-api.service'; +export { PeopleApiService } from './src/services/people-api.service'; +export { SearchApiService } from './src/services/search-api.service'; +export { SharedLinksApiService } from './src/services/shared-links-api.service'; +export { SitesApiService } from './src/services/sites-api.service'; + import { DataColumnListComponent } from './src/components/data-column/data-column-list.component'; import { DataColumnComponent } from './src/components/data-column/data-column.component'; import { UploadDirective } from './src/directives/upload.directive'; diff --git a/ng2-components/ng2-alfresco-core/src/services/deleted-nodes-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/deleted-nodes-api.service.ts new file mode 100644 index 0000000000..6383b924ef --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/deleted-nodes-api.service.ts @@ -0,0 +1,54 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; + +import { NodePaging } from 'alfresco-js-api'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { UserPreferencesService } from './user-preferences.service'; + +@Injectable() +export class DeletedNodesApiService { + constructor( + private apiService: AlfrescoApiService, + private preferences: UserPreferencesService + ) {} + + private get nodesApi() { + return this.apiService.getInstance().core.nodesApi; + } + + getDeletedNodes(options?: Object): Observable { + const { nodesApi, handleError } = this; + const defaultOptions = { + include: [ 'path', 'properties' ], + maxItems: this.preferences.paginationSize, + skipCount: 0 + }; + const queryOptions = Object.assign(defaultOptions, options); + const promise = nodesApi.getDeletedNodes(queryOptions); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + private handleError(error: any): Observable { + return Observable.of(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/favorites-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/favorites-api.service.ts new file mode 100644 index 0000000000..c36adb4bfd --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/favorites-api.service.ts @@ -0,0 +1,87 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { NodePaging } from 'alfresco-js-api'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { UserPreferencesService } from './user-preferences.service'; + +@Injectable() +export class FavoritesApiService { + private remapFavoritesData(data: any = {}): NodePaging { + const list = (data.list || {}); + const pagination = (list.pagination || {}); + const entries: any[] = this.remapFavoriteEntries(list.entries || []); + + return { + list: { entries, pagination } + }; + } + + private remapEntry({ entry }: any): any { + entry.createdAt = new Date(entry.createdAt); + entry.modifiedAt = new Date(entry.modifiedAt); + + entry.properties = { + 'cm:title': entry.title, + 'cm:description': entry.description + }; + + return { entry }; + } + + private remapFavoriteEntries(entries: any[]) { + return entries + .map(({ entry: { target }}: any) => ({ + entry: target.file || target.folder + })) + .filter(({ entry }) => (!!entry)) + .map(this.remapEntry); + } + + constructor( + private apiService: AlfrescoApiService, + private preferences: UserPreferencesService + ) {} + + private get favoritesApi() { + return this.apiService.getInstance().core.favoritesApi; + } + + getFavorites(personId: string, options?: any): Observable { + const { favoritesApi, handleError } = this; + const defaultOptions = { + maxItems: this.preferences.paginationSize, + skipCount: 0, + where: '(EXISTS(target/file) OR EXISTS(target/folder))', + include: [ 'properties', 'allowableOperations' ] + }; + const queryOptions = Object.assign(defaultOptions, options); + const promise = favoritesApi + .getFavorites(personId, queryOptions) + .then(this.remapFavoritesData); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + private handleError(error): Observable { + return Observable.of(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/nodes-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/nodes-api.service.ts new file mode 100644 index 0000000000..118a863f98 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/nodes-api.service.ts @@ -0,0 +1,117 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging } from 'alfresco-js-api'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { UserPreferencesService } from './user-preferences.service'; + +@Injectable() +export class NodesApiService { + + constructor( + private api: AlfrescoApiService, + private preferences: UserPreferencesService) {} + + private get nodesApi() { + return this.api.getInstance().core.nodesApi; + } + + private getEntryFromEntity(entity: MinimalNodeEntity) { + return entity.entry; + } + + getNode(nodeId: string, options: any = {}): Observable { + const { nodesApi, handleError, getEntryFromEntity } = this; + const defaults = { + include: [ 'path', 'properties', 'allowableOperations' ] + }; + const queryOptions = Object.assign(defaults, options); + const promise = nodesApi + .getNode(nodeId, queryOptions) + .then(getEntryFromEntity); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + getNodeChildren(nodeId: string, options: any = {}): Observable { + const { nodesApi, handleError } = this; + const defaults = { + maxItems: this.preferences.paginationSize, + skipCount: 0, + include: [ 'path', 'properties', 'allowableOperations' ] + }; + const queryOptions = Object.assign(defaults, options); + const promise = nodesApi + .getNodeChildren(nodeId, queryOptions); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + createNode(parentNodeId: string, nodeBody: any, options: any = {}): Observable { + const { nodesApi, handleError, getEntryFromEntity } = this; + const promise = nodesApi + .addNode(parentNodeId, nodeBody, options) + .then(getEntryFromEntity); + + return Observable.fromPromise(promise).catch(handleError); + } + + createFolder(parentNodeId: string, nodeBody: any, options: any = {}): Observable { + const body = Object.assign({ nodeType: 'cm:folder' }, nodeBody); + return this.createNode(parentNodeId, body, options); + } + + updateNode(nodeId: string, nodeBody: any, options: any = {}): Observable { + const { nodesApi, handleError, getEntryFromEntity } = this; + const promise = nodesApi + .updateNode(nodeId, nodeBody, options) + .then(getEntryFromEntity); + + return Observable.fromPromise(promise).catch(handleError); + } + + deleteNode(nodeId: string, options: any = {}): Observable { + const { nodesApi, handleError } = this; + const promise = nodesApi + .deleteNode(nodeId, options); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + restoreNode(nodeId: string): Observable { + const { nodesApi, handleError, getEntryFromEntity } = this; + const promise = nodesApi + .restoreNode(nodeId) + .then(getEntryFromEntity); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + handleError(error: any): Observable { + return Observable.throw(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/people-api.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/people-api.service.spec.ts new file mode 100644 index 0000000000..38e2e9556d --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/people-api.service.spec.ts @@ -0,0 +1,114 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, inject, TestBed } from '@angular/core/testing'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { PeopleApiService } from './people-api.service'; + +class PeopleApiServiceTest { + service: any = null; + setup: any = { + rejectGetPerson: false + }; + + constructor(setup: any = {}) { + Object.assign(this.setup, setup); + + const { alfrescoApiServiceMock } = this; + + const alfrescoApiServiceProvider = { + provide: AlfrescoApiService, + useValue: alfrescoApiServiceMock + }; + + TestBed.configureTestingModule({ + providers: [ + alfrescoApiServiceProvider, + PeopleApiService + ] + }); + + inject([ PeopleApiService ], (service) => { + this.service = service; + })(); + } + + private get alfrescoApiServiceMock(): any { + const { setup } = this; + + const peopleApiMock = { + getPerson: jasmine.createSpy('getPersonSpy').and.callFake((personId) => { + return new Promise((resolve, reject) => { + setup.rejectGetPerson + ? reject() + : resolve({ id: personId }); + }); + }) + }; + + return { + getInstance: () => { + return { + core: { peopleApi: peopleApiMock } + }; + } + }; + } + + get peopleApiGetPersonSpy() { + return this.service.peopleApi.getPerson; + } + + get peopleApiGetPersonArguments() { + return this.peopleApiGetPersonSpy.calls.mostRecent().args; + } +} + +describe('PeopleAPI', () => { + describe('Get persons', () => { + it('calls method by an id', async(() => { + const test = new PeopleApiServiceTest(); + + test.service.getPerson('person-1').subscribe(() => { + expect(test.peopleApiGetPersonArguments[0]) + .toBe('person-1'); + }); + })); + + it('calls method with "-me-"', async(() => { + const test = new PeopleApiServiceTest(); + + test.service.getCurrentPerson().subscribe(() => { + expect(test.peopleApiGetPersonArguments[0]) + .toBe('-me-'); + }); + })); + + it('handles the error when it fails', async(() => { + const test = new PeopleApiServiceTest({ + rejectGetPerson: true + }); + + const handleErrorSpy = spyOn(test.service, 'handleError') + .and.callThrough(); + + test.service.getPerson().subscribe(() => { + expect(handleErrorSpy).toHaveBeenCalled(); + }); + })); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/services/people-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/people-api.service.ts new file mode 100644 index 0000000000..89bd9d95b3 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/people-api.service.ts @@ -0,0 +1,47 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoApiService } from './alfresco-api.service'; + +@Injectable() +export class PeopleApiService { + + constructor(private apiService: AlfrescoApiService) {} + + private get peopleApi() { + return this.apiService.getInstance().core.peopleApi; + } + + getPerson(personId: string): Observable { + const { peopleApi, handleError } = this; + const promise = peopleApi.getPerson(personId); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + getCurrentPerson(): Observable { + return this.getPerson('-me-'); + } + + private handleError(error): Observable { + return Observable.of(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/search-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/search-api.service.ts new file mode 100644 index 0000000000..52671b9d25 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/search-api.service.ts @@ -0,0 +1,46 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; + +import { NodePaging } from 'alfresco-js-api'; +import { AlfrescoApiService } from './alfresco-api.service'; + +@Injectable() +export class SearchApiService { + + constructor(private apiService: AlfrescoApiService) {} + + private get searchApi() { + return this.apiService.getInstance().search.searchApi; + } + + search(query: any): Observable { + const { searchApi, handleError } = this; + const searchQuery = Object.assign(query); + const promise = searchApi.search(searchQuery); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + private handleError(error): Observable { + return Observable.of(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.spec.ts new file mode 100644 index 0000000000..7f2e751b31 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.spec.ts @@ -0,0 +1,169 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, inject, TestBed } from '@angular/core/testing'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { AppConfigModule } from './app-config.service'; +import { SharedLinksApiService } from './shared-links-api.service'; +import { StorageService } from './storage.service'; +import { UserPreferencesService } from './user-preferences.service'; + +class TestConfig { + service: any = null; + setup: any = { + rejectFindSharedLinks: false + }; + + constructor(setup: any = {}) { + Object.assign(this.setup, setup); + + const { alfrescoApiServiceMock } = this; + + const alfrescoApiServiceProvider = { + provide: AlfrescoApiService, + useValue: alfrescoApiServiceMock + }; + + TestBed.configureTestingModule({ + imports: [ + AppConfigModule.forRoot('app.config.json', { + pagination: { + size: 20 + } + }) + ], + providers: [ + alfrescoApiServiceProvider, + SharedLinksApiService, + StorageService, + UserPreferencesService + ] + }); + + inject([ SharedLinksApiService ], (service: SharedLinksApiService) => { + this.service = service; + })(); + } + + private get alfrescoApiServiceMock(): any { + const { setup } = this; + + const nodePagingSample = { + list: { + entries: [ + { entry: {} }, + { entry: {} } + ], + pagination: {} + } + }; + + const sharedLinksApiMock = { + findSharedLinks: jasmine.createSpy('findSharedLinks').and.callFake(() => { + return new Promise((resolve, reject) => { + setup.rejectFindSharedLinks + ? reject() + : resolve(nodePagingSample); + }); + }) + }; + + return { + getInstance: () => { + return { + core: { sharedlinksApi: sharedLinksApiMock } + }; + } + }; + } + + get findSharedLinksSpy(): any { + return this.service.sharedLinksApi.findSharedLinks; + } + + get findSharedLinksArgs(): any[] { + return this.findSharedLinksSpy.calls.mostRecent().args; + } +} + +describe('SharedLinks API', () => { + describe('getSharedLinks', () => { + describe('Provide a NodePaging', () => { + beforeEach(() => { + this.config = new TestConfig(); + }); + + it('provides a node paging with entries', async(() => { + this.config.service.getSharedLinks().subscribe((paging) => { + const { list: { entries, pagination } } = paging; + + expect(entries).toEqual(jasmine.any(Array)); + expect(pagination).toEqual(jasmine.any(Object)); + expect(entries.length).toBe(2); + }); + })); + }); + + describe('Manage query options', () => { + beforeEach(() => { + this.config = new TestConfig(); + + this.getCalledArgs = () => { + return this.config.findSharedLinksArgs; + }; + }); + + it('has default options', async(() => { + this.config.service.getSharedLinks(); + + const [ { maxItems, skipCount } ] = this.getCalledArgs(); + + expect(maxItems).toBe(20); + expect(skipCount).toBe(0); + })); + + it('combines custom and default options', async(() => { + this.config.service.getSharedLinks({ + maxItems: 5 + }); + + const [ { maxItems, skipCount } ] = this.getCalledArgs(); + + expect(maxItems).toBe(5); + expect(skipCount).toBe(0); + })); + }); + + describe('Error handling', () => { + beforeEach(() => { + const config = new TestConfig({ + rejectFindSharedLinks: true + }); + + this.service = config.service; + this.spy = spyOn(config.service, 'handleError') + .and.callThrough(); + }); + + it('handles error on failure', async(() => { + this.service.getSharedLinks().subscribe(() => { + expect(this.spy).toHaveBeenCalled(); + }); + })); + }); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.ts new file mode 100644 index 0000000000..3033add887 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/shared-links-api.service.ts @@ -0,0 +1,54 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { NodePaging } from 'alfresco-js-api'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { UserPreferencesService } from './user-preferences.service'; + +@Injectable() +export class SharedLinksApiService { + + constructor( + private apiService: AlfrescoApiService, + private preferences: UserPreferencesService) {} + + private get sharedLinksApi() { + return this.apiService.getInstance().core.sharedlinksApi; + } + + getSharedLinks(options: any = {}): Observable { + const { sharedLinksApi, handleError } = this; + const defaultOptions = { + maxItems: this.preferences.paginationSize, + skipCount: 0, + include: [ 'properties', 'allowableOperations' ] + }; + const queryOptions = Object.assign({}, defaultOptions, options); + const promise = sharedLinksApi + .findSharedLinks(queryOptions); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + private handleError(error: any): Observable { + return Observable.of(error); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/sites-api.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/sites-api.service.spec.ts new file mode 100644 index 0000000000..69a144f0c9 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/sites-api.service.spec.ts @@ -0,0 +1,171 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, inject, TestBed } from '@angular/core/testing'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { AppConfigModule } from './app-config.service'; +import { NodesApiService } from './nodes-api.service'; +import { SitesApiService } from './sites-api.service'; +import { StorageService } from './storage.service'; +import { UserPreferencesService } from './user-preferences.service'; + +class TestConfig { + service: any = null; + setup: any = { + rejectGetSites: false + }; + + constructor(setup: any = {}) { + Object.assign(this.setup, setup); + + const { alfrescoApiServiceMock } = this; + + const alfrescoApiServiceProvider = { + provide: AlfrescoApiService, + useValue: alfrescoApiServiceMock + }; + + TestBed.configureTestingModule({ + imports: [ + AppConfigModule.forRoot('app.config.json', { + pagination: { + size: 20 + } + }) + ], + providers: [ + alfrescoApiServiceProvider, + SitesApiService, + NodesApiService, + UserPreferencesService, + StorageService + ] + }); + + inject([ SitesApiService ], (service: SitesApiService) => { + this.service = service; + })(); + } + + private get alfrescoApiServiceMock(): any { + const { setup } = this; + + const nodePagingSample = { + list: { + entries: [ + { entry: {} }, + { entry: {} } + ], + pagination: {} + } + }; + + const sitesApiMock = { + getSites: jasmine.createSpy('getSites').and.callFake(() => { + return new Promise((resolve, reject) => { + setup.rejectGetSites + ? reject() + : resolve(nodePagingSample); + }); + }) + }; + + return { + getInstance: () => { + return { + core: { sitesApi: sitesApiMock } + }; + } + }; + } + + get getSitesSpy(): any { + return this.service.sitesApi.getSites; + } + + get getSitesArgs(): any[] { + return this.getSitesSpy.calls.mostRecent().args; + } +} + +describe('Sites API', () => { + describe('getSites', () => { + describe('Provide a NodePaging', () => { + beforeEach(() => { + this.config = new TestConfig(); + }); + + it('provides a node paging with entries', async(() => { + this.config.service.getSites().subscribe((paging) => { + const { list: { entries, pagination } } = paging; + + expect(entries).toEqual(jasmine.any(Array)); + expect(pagination).toEqual(jasmine.any(Object)); + expect(entries.length).toBe(2); + }); + })); + }); + + describe('Manage query options', () => { + beforeEach(() => { + this.config = new TestConfig(); + + this.getCalledArgs = () => { + return this.config.getSitesArgs; + }; + }); + + it('has default options', async(() => { + this.config.service.getSites(); + + const [ { maxItems, skipCount } ] = this.getCalledArgs(); + + expect(maxItems).toBe(20); + expect(skipCount).toBe(0); + })); + + it('combines custom and default options', async(() => { + this.config.service.getSites({ + maxItems: 5 + }); + + const [ { maxItems, skipCount } ] = this.getCalledArgs(); + + expect(maxItems).toBe(5); + expect(skipCount).toBe(0); + })); + }); + + describe('Error handling', () => { + beforeEach(() => { + const config = new TestConfig({ + rejectGetSites: true + }); + + this.service = config.service; + this.spy = spyOn(config.service, 'handleError') + .and.callThrough(); + }); + + it('handles error on failure', async(() => { + this.service.getSites().subscribe(() => { + expect(this.spy).toHaveBeenCalled(); + }); + })); + }); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/services/sites-api.service.ts b/ng2-components/ng2-alfresco-core/src/services/sites-api.service.ts new file mode 100644 index 0000000000..ffee629adb --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/sites-api.service.ts @@ -0,0 +1,62 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { MinimalNodeEntryEntity, NodePaging } from 'alfresco-js-api'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { NodesApiService } from './nodes-api.service'; +import { UserPreferencesService } from './user-preferences.service'; + +@Injectable() +export class SitesApiService { + + constructor( + private apiService: AlfrescoApiService, + private nodesApi: NodesApiService, + private preferences: UserPreferencesService) {} + + private get sitesApi() { + return this.apiService.getInstance().core.sitesApi; + } + + getSites(options: any = {}): Observable { + const { sitesApi, handleError } = this; + const defaultOptions = { + maxItems: this.preferences.paginationSize, + skipCount: 0, + include: [ 'properties' ] + }; + const queryOptions = Object.assign({}, defaultOptions, options); + const promise = sitesApi.getSites(queryOptions); + + return Observable + .fromPromise(promise) + .catch(handleError); + } + + getSiteDocumentLibrary(siteId: string): Observable { + const { nodesApi } = this; + + return nodesApi + .getNode(siteId, { relativePath: '/documentLibrary' }); + } + + private handleError(error: any): Observable { + return Observable.of(error); + } +}