diff --git a/docs/content-services/services/tag.service.md b/docs/content-services/services/tag.service.md index e067f2eba3..0ba9bd8107 100644 --- a/docs/content-services/services/tag.service.md +++ b/docs/content-services/services/tag.service.md @@ -31,6 +31,16 @@ Manages tags in Content Services. - _nodeId:_ `string` - ID of the target node - _tag:_ `string` - Name of the tag to remove - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`` - Null object when the operation completes +- **createTags**(tags: `TagBody[]`): [`Observable`](http://reactivex.io/documentation/observable.html)``
+ Creates tags. + - _tags:_ `TagBody[]` - List of tags to create. + - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`` - List of created tags. +- **searchTags**(name: `string`, skipCount: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)``
+ Find tags which name contains searched name. + - _name:_ `string` - Value for name which should be used during searching tags. + - _skipCount:_ `number` - Specify how many first results should be skipped. Default 0. + - _maxItems:_ `number` - Specify max number of returned tags. Default is specified by UserPreferencesService. + - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`` - Found tags which name contains searched name. ## Details diff --git a/lib/content-services/src/lib/tag/services/tag.service.spec.ts b/lib/content-services/src/lib/tag/services/tag.service.spec.ts index 89412e021d..dbc5cd3bda 100644 --- a/lib/content-services/src/lib/tag/services/tag.service.spec.ts +++ b/lib/content-services/src/lib/tag/services/tag.service.spec.ts @@ -15,13 +15,21 @@ * limitations under the License. */ -import { setupTestBed } from '@alfresco/adf-core'; +import { LogService, setupTestBed, UserPreferencesService } from '@alfresco/adf-core'; import { TagService } from './tag.service'; -import { TestBed } from '@angular/core/testing'; +import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { ContentTestingModule } from '../../testing/content.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { throwError } from 'rxjs'; -import { TagEntry } from '@alfresco/js-api'; +import { + RequestQuery, + RequestSortDefinitionInner, + ResultSetPaging, + SearchApi, + SearchRequest, + TagBody, + TagEntry +} from '@alfresco/js-api'; describe('TagService', () => { @@ -70,5 +78,95 @@ describe('TagService', () => { service.addTag('fake-node-id', 'fake-tag'); }); + + describe('createTags', () => { + it('should call createTags on tagsApi', () => { + spyOn(service.tagsApi, 'createTags').and.returnValue(Promise.resolve([])); + const tag1: TagBody = new TagBody(); + tag1.tag = 'Some tag 1'; + const tag2: TagBody = new TagBody(); + tag2.tag = 'Some tag 2'; + const tags: TagBody[] = [tag1, tag2]; + service.createTags(tags); + expect(service.tagsApi.createTags).toHaveBeenCalledWith(tags); + }); + + it('should emit refresh when tags creation is success', fakeAsync(() => { + const tags: TagEntry[] = [{ + entry: { + id: 'Some id 1', + tag: 'Some tag 1' + } + }]; + spyOn(service.refresh, 'emit'); + spyOn(service.tagsApi, 'createTags').and.returnValue(Promise.resolve(tags)); + service.createTags([]); + tick(); + expect(service.refresh.emit).toHaveBeenCalledWith(tags); + })); + + it('should call error on logService when error occurs during tags creation', fakeAsync(() => { + const logService: LogService = TestBed.inject(LogService); + spyOn(logService, 'error'); + const error: string = 'Some error'; + spyOn(service.tagsApi, 'createTags').and.returnValue(Promise.reject(error)); + service.createTags([]); + tick(); + expect(logService.error).toHaveBeenCalledWith(error); + })); + }); + + describe('searchTags', () => { + let result: ResultSetPaging; + + beforeEach(() => { + result = new ResultSetPaging(); + }); + + it('should call search on searchApi with correct parameters', () => { + const searchSpy: jasmine.Spy<(queryBody: SearchRequest) => Promise> = + spyOn(SearchApi.prototype, 'search').and.returnValue(Promise.resolve(result)); + const name: string = 'test'; + const sortingByName: RequestSortDefinitionInner = new RequestSortDefinitionInner(); + const maxItems: number = 25; + spyOnProperty(TestBed.inject(UserPreferencesService), 'paginationSize').and.returnValue(maxItems); + sortingByName.field = 'cm:name'; + sortingByName.ascending = true; + sortingByName.type = RequestSortDefinitionInner.TypeEnum.FIELD; + service.searchTags(name); + expect(searchSpy).toHaveBeenCalledWith({ + query: { + language: RequestQuery.LanguageEnum.Afts, + query: `PATH:"/cm:categoryRoot/cm:taggable/*" AND cm:name:"${name}*"` + }, + paging: { + skipCount: 0, + maxItems + }, + sort: [sortingByName] + }); + }); + + it('should return observable which emits paging object for tags', (done) => { + spyOn(SearchApi.prototype, 'search').and.returnValue(Promise.resolve(result)); + service.searchTags('test').subscribe((tagsResult) => { + expect(tagsResult).toBe(result); + done(); + }); + }); + + it('should call error on logService when error occurs during fetching paging object for tags', fakeAsync(() => { + const logService: LogService = TestBed.inject(LogService); + spyOn(logService, 'error'); + const error: string = 'Some error'; + spyOn(SearchApi.prototype, 'search').and.returnValue(Promise.reject(error)); + service.searchTags('test').subscribe({ + error: () => { + expect(logService.error).toHaveBeenCalledWith(error); + } + }); + tick(); + })); + }); }); }); diff --git a/lib/content-services/src/lib/tag/services/tag.service.ts b/lib/content-services/src/lib/tag/services/tag.service.ts index 976aca2caf..9632628ef1 100644 --- a/lib/content-services/src/lib/tag/services/tag.service.ts +++ b/lib/content-services/src/lib/tag/services/tag.service.ts @@ -15,11 +15,20 @@ * limitations under the License. */ -import { AlfrescoApiService, LogService } from '@alfresco/adf-core'; +import { AlfrescoApiService, LogService, UserPreferencesService } from '@alfresco/adf-core'; import { EventEmitter, Injectable, Output } from '@angular/core'; -import { Observable, from, throwError } from 'rxjs'; +import { from, Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; -import { TagBody, TagPaging, TagEntry, TagsApi } from '@alfresco/js-api'; +import { + RequestQuery, + RequestSortDefinitionInner, + ResultSetPaging, + SearchApi, + TagBody, + TagEntry, + TagPaging, + TagsApi +} from '@alfresco/js-api'; @Injectable({ providedIn: 'root' @@ -33,12 +42,15 @@ export class TagService { return this._tagsApi; } + private searchApi: SearchApi = new SearchApi(this.apiService.getInstance()); + /** Emitted when tag information is updated. */ @Output() refresh = new EventEmitter(); constructor(private apiService: AlfrescoApiService, - private logService: LogService) { + private logService: LogService, + private userPreferencesService: UserPreferencesService) { } /** @@ -105,6 +117,47 @@ export class TagService { return observableRemove; } + /** + * Creates tags. + * + * @param tags list of tags to create. + * @returns Created tags. + */ + createTags(tags: TagBody[]): Observable { + const observableAdd$: Observable = from(this.tagsApi.createTags(tags)); + observableAdd$.subscribe( + (tagsEntries: TagEntry[]) => this.refresh.emit(tagsEntries), + (err) => this.handleError(err) + ); + return observableAdd$; + } + + /** + * Find tags which name contains searched name. + * + * @param name Value for name which should be used during searching tags. + * @param skipCount Specify how many first results should be skipped. Default 0. + * @param maxItems Specify max number of returned tags. Default is specified by UserPreferencesService. + * @returns Found tags which name contains searched name. + */ + searchTags(name: string, skipCount: number = 0, maxItems: number = this.userPreferencesService.paginationSize): Observable { + const sortingByName: RequestSortDefinitionInner = new RequestSortDefinitionInner(); + sortingByName.field = 'cm:name'; + sortingByName.ascending = true; + sortingByName.type = RequestSortDefinitionInner.TypeEnum.FIELD; + return from(this.searchApi.search({ + query: { + language: RequestQuery.LanguageEnum.Afts, + query: `PATH:"/cm:categoryRoot/cm:taggable/*" AND cm:name:"${name}*"` + }, + paging: { + skipCount, + maxItems + }, + sort: [sortingByName] + })).pipe(catchError((error) => this.handleError(error))); + } + private handleError(error: any) { this.logService.error(error); return throwError(error || 'Server error'); diff --git a/package-lock.json b/package-lock.json index c6968361e7..6531918b54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alfresco/js-api": { - "version": "5.3.0-528", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-528.tgz", - "integrity": "sha512-VJjPhP+parntmRxOMmTc5hoZfEsem+dlBoJDrSWBNvjC5Yq80lQ/YptUZW8UKOblrmmTde30FOy0UMUXO02cYA==", + "version": "5.3.0-536", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-5.3.0-536.tgz", + "integrity": "sha512-nGyFRsA0rLYRqSQbjNBpDa9oDG0LCk7rvA9pmfyeoCCwDNhKp2INtsGhcQvV32OaRuHN82gTuvS6SSrQs5eeMg==", "requires": { "event-emitter": "^0.3.5", "minimatch": "5.0.1", diff --git a/package.json b/package.json index 06d6119ad3..8fbff105e0 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "process services-cloud" ], "dependencies": { - "@alfresco/js-api": "5.3.0-528", + "@alfresco/js-api": "5.3.0-536", "@angular/animations": "14.1.3", "@angular/cdk": "14.1.2", "@angular/common": "14.1.3",