[ACS-4118] create a tag from tags list (#8143)

* ACS-4118 Update service for tags creation

* ACS-4118 Added unit tests and documentation

* ACS-4118 Added function in tag service for searching tags

* ACS-4118 Moved imported class to new line

* ACS-4118 Use UserPreferencesService for setting maxItems

* ACS-4118 Allow to specify maxItems

* ACS-4118 Added missing type

* ACS-4118 Increased js-api version
This commit is contained in:
AleksanderSklorz 2023-01-16 09:50:30 +01:00 committed by GitHub
parent bbee01a809
commit 616ae95c23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 172 additions and 11 deletions

View File

@ -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)`<any>` - Null object when the operation completes
- **createTags**(tags: `TagBody[]`): [`Observable`](http://reactivex.io/documentation/observable.html)`<TagEntry[]>`<br/>
Creates tags.
- _tags:_ `TagBody[]` - List of tags to create.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<TagEntry[]>` - List of created tags.
- **searchTags**(name: `string`, skipCount: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)`<ResultSetPaging>`<br/>
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)`<ResultSetPaging>` - Found tags which name contains searched name.
## Details

View File

@ -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<ResultSetPaging>> =
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();
}));
});
});
});

View File

@ -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<TagEntry[]> {
const observableAdd$: Observable<TagEntry[]> = 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<ResultSetPaging> {
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');

6
package-lock.json generated
View File

@ -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",

View File

@ -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",