diff --git a/lib/content-services/src/lib/api-factories/alfresco-api-no-auth.service.ts b/lib/content-services/src/lib/api-factories/alfresco-api-no-auth.service.ts index 1530ccbd47c..bfd6a849d8b 100644 --- a/lib/content-services/src/lib/api-factories/alfresco-api-no-auth.service.ts +++ b/lib/content-services/src/lib/api-factories/alfresco-api-no-auth.service.ts @@ -15,26 +15,24 @@ * limitations under the License. */ -import { AdfHttpClient } from '@alfresco/adf-core/api'; -import { StorageService, AppConfigService } from '@alfresco/adf-core'; import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { Injectable } from '@angular/core'; import { AlfrescoApiService } from '../services/alfresco-api.service'; +/** @deprecated use `AlfrescoApiService` instead */ @Injectable() export class AlfrescoApiNoAuthService extends AlfrescoApiService { - constructor( - storage: StorageService, - appConfig: AppConfigService, - private readonly adfHttpClient: AdfHttpClient - ) { - super(appConfig, storage); + constructor() { + super(); } override createInstance(config: AlfrescoApiConfig) { - return new AlfrescoApi({ - ...config, - oauthInit: false - }, this.adfHttpClient); + return new AlfrescoApi( + { + ...config, + oauthInit: false + }, + this.adfHttpClient + ); } } diff --git a/lib/content-services/src/lib/common/services/upload.service.spec.ts b/lib/content-services/src/lib/common/services/upload.service.spec.ts index 4f602abaefd..71d653ea564 100644 --- a/lib/content-services/src/lib/common/services/upload.service.spec.ts +++ b/lib/content-services/src/lib/common/services/upload.service.spec.ts @@ -17,7 +17,7 @@ import { EventEmitter } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { AppConfigModule, AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core'; +import { AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core'; import { UploadService } from './upload.service'; import { RepositoryInfo } from '@alfresco/js-api'; import { BehaviorSubject } from 'rxjs'; @@ -26,6 +26,7 @@ import { FileModel, FileUploadStatus } from '../../common/models/file.model'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { AlfrescoApiService } from '../../services'; import { AlfrescoApiServiceMock } from '../../mock'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -38,11 +39,13 @@ describe('UploadService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AppConfigModule, HttpClientTestingModule], + imports: [HttpClientTestingModule], providers: [ UploadService, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, { provide: AppConfigService, useClass: AppConfigServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null }, { provide: DiscoveryApiService, useValue: { diff --git a/lib/content-services/src/lib/content.module.ts b/lib/content-services/src/lib/content.module.ts index e283dbbfe2d..b1ef73e9cb2 100644 --- a/lib/content-services/src/lib/content.module.ts +++ b/lib/content-services/src/lib/content.module.ts @@ -46,8 +46,6 @@ import { AlfrescoViewerComponent } from './viewer'; import { ContentTypeDialogComponent } from './content-type'; import { MaterialModule } from './material.module'; import { AlfrescoIconComponent } from './alfresco-icon/alfresco-icon.component'; -import { AlfrescoApiService } from './services/alfresco-api.service'; -import { AlfrescoApiNoAuthService } from './api-factories/alfresco-api-no-auth.service'; import { AlfrescoApiLoaderService, createAlfrescoApiInstance } from './api-factories/alfresco-api-v2-loader.service'; @NgModule({ @@ -114,7 +112,6 @@ export class ContentModule { providers: [ provideTranslations('adf-content-services', 'assets/adf-content-services'), ContentAuthLoaderService, - { provide: AlfrescoApiService, useClass: AlfrescoApiNoAuthService }, { provide: APP_INITIALIZER, useFactory: versionCompatibilityFactory, diff --git a/lib/content-services/src/lib/document-list/services/document-list.service.spec.ts b/lib/content-services/src/lib/document-list/services/document-list.service.spec.ts index 20d8d4c0914..476dc9807cc 100644 --- a/lib/content-services/src/lib/document-list/services/document-list.service.spec.ts +++ b/lib/content-services/src/lib/document-list/services/document-list.service.spec.ts @@ -18,6 +18,7 @@ import { DocumentListService } from './document-list.service'; import { fakeAsync, TestBed } from '@angular/core/testing'; import { ContentTestingModule } from '../../testing/content.testing.module'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -68,7 +69,11 @@ describe('DocumentListService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ContentTestingModule] + imports: [ContentTestingModule], + providers: [ + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); service = TestBed.inject(DocumentListService); jasmine.Ajax.install(); diff --git a/lib/content-services/src/lib/mock/alfresco-api.service.mock.ts b/lib/content-services/src/lib/mock/alfresco-api.service.mock.ts index 043dff72952..bcbb8754331 100644 --- a/lib/content-services/src/lib/mock/alfresco-api.service.mock.ts +++ b/lib/content-services/src/lib/mock/alfresco-api.service.mock.ts @@ -17,14 +17,12 @@ import { Injectable } from '@angular/core'; import { AlfrescoApiService } from '../services/alfresco-api.service'; -import { AppConfigService, StorageService } from '@alfresco/adf-core'; @Injectable() export class AlfrescoApiServiceMock extends AlfrescoApiService { + constructor() { + super(); - constructor(protected appConfig: AppConfigService, - protected storageService: StorageService) { - super(appConfig, storageService); if (!this.alfrescoApi) { this.initAlfrescoApi(); } diff --git a/lib/content-services/src/lib/node-comments/services/node-comments.service.spec.ts b/lib/content-services/src/lib/node-comments/services/node-comments.service.spec.ts index 979db2c9de0..f52d030b4b8 100644 --- a/lib/content-services/src/lib/node-comments/services/node-comments.service.spec.ts +++ b/lib/content-services/src/lib/node-comments/services/node-comments.service.spec.ts @@ -23,6 +23,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { EMPTY, of } from 'rxjs'; import { AlfrescoApiService } from '../../services'; import { AlfrescoApiServiceMock } from '../../mock'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -34,7 +35,9 @@ describe('NodeCommentsService', () => { imports: [HttpClientTestingModule], providers: [ { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, - { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } } + { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } ] }); service = TestBed.inject(NodeCommentsService); diff --git a/lib/content-services/src/lib/services/alfresco-api.service.spec.ts b/lib/content-services/src/lib/services/alfresco-api.service.spec.ts new file mode 100644 index 00000000000..07ae8ad9dcf --- /dev/null +++ b/lib/content-services/src/lib/services/alfresco-api.service.spec.ts @@ -0,0 +1,52 @@ +/*! + * @license + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { TestBed } from '@angular/core/testing'; +import { AlfrescoApiService } from './alfresco-api.service'; +import { AppConfigService, StorageService } from '@alfresco/adf-core'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; + +describe('AlfrescoApiService', () => { + let service: AlfrescoApiService; + + beforeEach(() => { + const appConfigSpy = jasmine.createSpyObj('AppConfigService', ['get']); + const storageSpy = jasmine.createSpyObj('StorageService', ['']); + + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [AlfrescoApiService, { provide: AppConfigService, useValue: appConfigSpy }, { provide: StorageService, useValue: storageSpy }] + }); + + service = TestBed.inject(AlfrescoApiService); + + service['lastConfig'] = { + hostBpm: 'http://localhost:8080', + contextRootBpm: 'activiti-app' + } as any; + }); + + it('should return true for excluded error URL', () => { + const currentFullPath = 'http://localhost:8080/activiti-app/api/enterprise/system/properties'; + expect(service.isExcludedErrorListener(currentFullPath)).toBeTrue(); + }); + + it('should return false for non-excluded error URL', () => { + const currentFullPath = 'http://localhost:8080/activiti-app/api/enterprise/other'; + expect(service.isExcludedErrorListener(currentFullPath)).toBeFalse(); + }); +}); diff --git a/lib/content-services/src/lib/services/alfresco-api.service.ts b/lib/content-services/src/lib/services/alfresco-api.service.ts index 24f7a60eef7..e4ff8257086 100644 --- a/lib/content-services/src/lib/services/alfresco-api.service.ts +++ b/lib/content-services/src/lib/services/alfresco-api.service.ts @@ -15,11 +15,12 @@ * limitations under the License. */ -import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; +import { inject, Injectable, InjectionToken } from '@angular/core'; import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { ReplaySubject } from 'rxjs'; import { AlfrescoApiFactory } from './alfresco-api.interface'; import { AppConfigService, AppConfigValues, OauthConfigModel, OpenidConfiguration, StorageService } from '@alfresco/adf-core'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; export const ALFRESCO_API_FACTORY = new InjectionToken('ALFRESCO_API_FACTORY'); @@ -27,6 +28,11 @@ export const ALFRESCO_API_FACTORY = new InjectionToken('ALFRESCO_API_FACTORY'); providedIn: 'root' }) export class AlfrescoApiService { + protected appConfig = inject(AppConfigService); + protected storageService = inject(StorageService); + protected alfrescoApiFactory = inject(ALFRESCO_API_FACTORY, { optional: true }); + protected adfHttpClient = inject(AdfHttpClient, { optional: true }); + alfrescoApiInitialized: ReplaySubject = new ReplaySubject(1); protected alfrescoApi: AlfrescoApi; @@ -36,20 +42,12 @@ export class AlfrescoApiService { idpConfig: OpenidConfiguration; - private excludedErrorUrl: string[] = ['api/enterprise/system/properties']; + private readonly excludedErrorUrl = ['/api/enterprise/system/properties']; getInstance(): AlfrescoApi { return this.alfrescoApi; } - constructor( - protected appConfig: AppConfigService, - protected storageService: StorageService, - @Optional() - @Inject(ALFRESCO_API_FACTORY) - private alfrescoApiFactory?: AlfrescoApiFactory - ) {} - async load(config: AlfrescoApiConfig): Promise { this.currentAppConfig = config; @@ -122,15 +120,26 @@ export class AlfrescoApiService { if (this.alfrescoApiFactory) { return this.alfrescoApiFactory.createAlfrescoApi(config); } - return new AlfrescoApi(config); + + return new AlfrescoApi( + { + ...config, + oauthInit: false + }, + this.adfHttpClient + ); } isDifferentConfig(lastConfig: AlfrescoApiConfig, newConfig: AlfrescoApiConfig) { return JSON.stringify(lastConfig) !== JSON.stringify(newConfig); } + private formatExcludedPath(path: string): string { + return path.replace(this.lastConfig.hostBpm + '/' + this.lastConfig.contextRootBpm, ''); + } + isExcludedErrorListener(currentFullPath: string): boolean { - const formattedPath = currentFullPath.replace(this.lastConfig.hostBpm + '/' + this.lastConfig.contextRootBpm, ''); + const formattedPath = this.formatExcludedPath(currentFullPath); return this.excludedErrorUrl.includes(formattedPath); } } diff --git a/lib/core/api/src/index.ts b/lib/core/api/src/index.ts index e5403a15a90..1dcc418e9e8 100644 --- a/lib/core/api/src/index.ts +++ b/lib/core/api/src/index.ts @@ -18,3 +18,4 @@ export * from './lib/types'; export * from './lib/adf-http-client.service'; export * from './lib/interfaces'; +export * from './lib/tokens'; diff --git a/lib/core/api/src/lib/adf-http-client.service.ts b/lib/core/api/src/lib/adf-http-client.service.ts index 30865ab2276..1030a21ceb5 100644 --- a/lib/core/api/src/lib/adf-http-client.service.ts +++ b/lib/core/api/src/lib/adf-http-client.service.ts @@ -15,17 +15,8 @@ * limitations under the License. */ -import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/auth'; import { Emitters as JsApiEmitters, HttpClient as JsApiHttpClient } from '@alfresco/js-api'; -import { - HttpClient, - HttpContext, - HttpErrorResponse, - HttpEvent, - HttpHeaders, - HttpParams, - HttpResponse -} from '@angular/common/http'; +import { HttpClient, HttpContext, HttpErrorResponse, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, of, Subject, throwError } from 'rxjs'; import { catchError, map, takeUntil } from 'rxjs/operators'; @@ -43,6 +34,7 @@ import { AlfrescoApiResponseError } from './alfresco-api/alfresco-api.response-e import { Constructor } from './types'; import { RequestOptions, SecurityOptions } from './interfaces'; import ee, { Emitter } from 'event-emitter'; +import { SHOULD_ADD_AUTH_TOKEN } from './tokens'; export interface Emitters { readonly eventEmitter: Emitter; @@ -52,8 +44,7 @@ export interface Emitters { @Injectable({ providedIn: 'root' }) -export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { - +export class AdfHttpClient implements ee.Emitter, JsApiHttpClient { on: ee.EmitterMethod; off: ee.EmitterMethod; once: ee.EmitterMethod; @@ -80,10 +71,23 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { ee(this); } + /** + * Update the default security options + * + * @param options security options + * @deprecated not used anywhere + */ setDefaultSecurityOption(options: any) { this.defaultSecurityOptions = this.merge(this.defaultSecurityOptions, options); } + /** + * Merge objects + * + * @param objects objects to merge + * @deprecated not used anywhere + * @returns merged object + */ merge(...objects): any { const result = {}; @@ -103,52 +107,48 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { } request(url: string, options?: RequestOptions, sc: SecurityOptions = this.defaultSecurityOptions, emitters?: JsApiEmitters): Promise { - const body = AdfHttpClient.getBody(options); + const body = this.getBody(options); const params = getQueryParamsWithCustomEncoder(options.queryParams, new AlfrescoApiParamEncoder()); - const responseType = AdfHttpClient.getResponseType(options); + const responseType = this.getResponseType(options); const context = new HttpContext().set(SHOULD_ADD_AUTH_TOKEN, true); - const security: SecurityOptions = {...this.defaultSecurityOptions, ...sc}; + const security: SecurityOptions = { ...this.defaultSecurityOptions, ...sc }; const headers = this.getHeaders(options); if (!emitters) { emitters = this.getEventEmitters(); } - const request = this.httpClient.request( - options.httpMethod, - url, - { - context, - ...(body && {body}), - ...(responseType && {responseType}), - ...security, - ...(params && {params}), - headers, - observe: 'events', - reportProgress: true - } - ); + const request = this.httpClient.request(options.httpMethod, url, { + context, + ...(body && { body }), + ...(responseType && { responseType }), + ...security, + ...(params && { params }), + headers, + observe: 'events', + reportProgress: true + }); return this.requestWithLegacyEventEmitters(request, emitters, options.returnType); } post(url: string, options?: RequestOptions, sc?: SecurityOptions, emitters?: JsApiEmitters): Promise { - return this.request(url, {...options, httpMethod: 'POST'}, sc, emitters); + return this.request(url, { ...options, httpMethod: 'POST' }, sc, emitters); } put(url: string, options?: RequestOptions, sc?: SecurityOptions, emitters?: JsApiEmitters): Promise { - return this.request(url, {...options, httpMethod: 'PUT'}, sc, emitters); + return this.request(url, { ...options, httpMethod: 'PUT' }, sc, emitters); } get(url: string, options?: RequestOptions, sc?: SecurityOptions, emitters?: JsApiEmitters): Promise { - return this.request(url, {...options, httpMethod: 'GET'}, sc, emitters); + return this.request(url, { ...options, httpMethod: 'GET' }, sc, emitters); } delete(url: string, options?: RequestOptions, sc?: SecurityOptions, emitters?: JsApiEmitters): Promise { - return this.request(url, {...options, httpMethod: 'DELETE'}, sc, emitters); + return this.request(url, { ...options, httpMethod: 'DELETE' }, sc, emitters); } - private addPromiseListeners(promise: Promise, eventEmitter: any) { - const eventPromise = Object.assign(promise, { + private addPromiseListeners(promise: Promise, eventEmitter: any) { + return Object.assign(promise, { on() { // eslint-disable-next-line prefer-spread, prefer-rest-params eventEmitter.on.apply(eventEmitter, arguments); @@ -170,8 +170,6 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { return this; } }); - - return eventPromise; } private getEventEmitters(): Emitters { @@ -189,58 +187,60 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { } private requestWithLegacyEventEmitters(request$: Observable>, emitters: JsApiEmitters, returnType: any): Promise { - const abort$ = new Subject(); - const {eventEmitter, apiClientEmitter} = emitters; - - const promise = request$.pipe( - map((res) => { - if (isHttpUploadProgressEvent(res)) { - const percent = Math.round((res.loaded / res.total) * 100); - eventEmitter.emit('progress', {loaded: res.loaded, total: res.total, percent}); - } - - if (isHttpResponseEvent(res)) { - eventEmitter.emit('success', res.body); - return AdfHttpClient.deserialize(res, returnType); - } - }), - catchError((err: HttpErrorResponse): Observable => { - - // since we can't always determinate ahead of time if the response is going to be xml or plain text response - // we need to handle false positive cases here. - - if (err.status === 200) { - eventEmitter.emit('success', err.error.text); - return of(err.error.text); - } - - eventEmitter.emit('error', err); - apiClientEmitter.emit('error', { ...err, response: { req: err } }); - - if (err.status === 401) { - eventEmitter.emit('unauthorized'); - apiClientEmitter.emit('unauthorized'); - } - - // for backwards compatibility we need to convert it to error class as the HttpErrorResponse only implements Error interface, not extending it, - // and we need to be able to correctly pass instanceof Error conditions used inside repository - // we also need to pass error as Stringify string as we are detecting statusCodes using JSON.parse(error.message) in some places - const msg = typeof err.error === 'string' ? err.error : JSON.stringify(err.error); - - // for backwards compatibility to handle cases in code where we try read response.error.response.body; - - const error = { - ...err, body: err.error - }; - - const alfrescoApiError = new AlfrescoApiResponseError(msg, err.status, error); - return throwError(alfrescoApiError); - }), - takeUntil(abort$) - ).toPromise(); - - (promise as any).abort = function() { + const { eventEmitter, apiClientEmitter } = emitters; + + const promise = request$ + .pipe( + map((res) => { + if (isHttpUploadProgressEvent(res)) { + const percent = Math.round((res.loaded / res.total) * 100); + eventEmitter.emit('progress', { loaded: res.loaded, total: res.total, percent }); + } + + if (isHttpResponseEvent(res)) { + eventEmitter.emit('success', res.body); + return this.deserialize(res, returnType); + } + }), + catchError((err: HttpErrorResponse): Observable => { + // since we can't always determinate ahead of time if the response is going to be xml or plain text response + // we need to handle false positive cases here. + + if (err.status === 200) { + eventEmitter.emit('success', err.error.text); + return of(err.error.text); + } + + eventEmitter.emit('error', err); + apiClientEmitter.emit('error', { ...err, response: { req: err } }); + + if (err.status === 401) { + eventEmitter.emit('unauthorized'); + apiClientEmitter.emit('unauthorized'); + } + + // for backwards compatibility we need to convert it to error class as the HttpErrorResponse only implements Error interface, not extending it, + // and we need to be able to correctly pass instanceof Error conditions used inside repository + // we also need to pass error as Stringify string as we are detecting statusCodes using JSON.parse(error.message) in some places + const msg = typeof err.error === 'string' ? err.error : JSON.stringify(err.error); + + // for backwards compatibility to handle cases in code where we try read response.error.response.body; + + const error = { + ...err, + body: err.error + }; + + const alfrescoApiError = new AlfrescoApiResponseError(msg, err.status, error); + return throwError(() => alfrescoApiError); + }), + takeUntil(abort$) + ) + .toPromise(); + + /* eslint-disable @typescript-eslint/space-before-function-paren */ + (promise as any).abort = function () { eventEmitter.emit('abort'); abort$.next(); abort$.complete(); @@ -250,8 +250,8 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { return this.addPromiseListeners(promise, eventEmitter); } - private static getBody(options: RequestOptions): any { - const contentType = options.contentType ? options.contentType : AdfHttpClient.jsonPreferredMime(options.contentTypes); + private getBody(options: RequestOptions): any { + const contentType = options.contentType ? options.contentType : this.jsonPreferredMime(options.contentTypes); const isFormData = contentType === 'multipart/form-data'; const isFormUrlEncoded = contentType === 'application/x-www-form-urlencoded'; const body = options.bodyParam; @@ -261,20 +261,20 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { } if (isFormUrlEncoded) { - return new HttpParams({fromObject: removeNilValues(options.formParams)}); + return new HttpParams({ fromObject: removeNilValues(options.formParams) }); } return body; } private getHeaders(options: RequestOptions): HttpHeaders { - const contentType = options.contentType || AdfHttpClient.jsonPreferredMime(options.contentTypes); - const accept = options.accept || AdfHttpClient.jsonPreferredMime(options.accepts); + const contentType = options.contentType || this.jsonPreferredMime(options.contentTypes); + const accept = options.accept || this.jsonPreferredMime(options.accepts); const optionsHeaders = { ...options.headerParams, - ...(accept && {Accept: accept}), - ...((contentType) && {'Content-Type': contentType}) + ...(accept && { Accept: accept }), + ...(contentType && { 'Content-Type': contentType }) }; if (!this.disableCsrf) { @@ -290,13 +290,13 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { * @param contentTypes a contentType array * @returns The chosen content type, preferring JSON. */ - private static jsonPreferredMime(contentTypes: readonly string[]): string { + private jsonPreferredMime(contentTypes: readonly string[]): string { if (!contentTypes?.length) { return 'application/json'; } for (let i = 0; i < contentTypes.length; i++) { - if (AdfHttpClient.isJsonMime(contentTypes[i])) { + if (this.isJsonMime(contentTypes[i])) { return contentTypes[i]; } } @@ -315,11 +315,10 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { * @param contentType The MIME content type to check. * @returns true if contentType represents JSON, otherwise false. */ - private static isJsonMime(contentType: string): boolean { + private isJsonMime(contentType: string): boolean { return Boolean(contentType?.match(/^application\/json(;.*)?$/i)); } - private setCsrfToken(optionsHeaders: any) { const token = this.createCSRFToken(); optionsHeaders['X-CSRF-TOKEN'] = token; @@ -336,8 +335,7 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { return a ? (a ^ ((randomValue * 16) >> (a / 4))).toString(16) : ([1e16] + (1e16).toString()).replace(/[01]/g, this.createCSRFToken); } - private static getResponseType(options: RequestOptions): 'blob' | 'json' | 'text' { - + private getResponseType(options: RequestOptions): 'blob' | 'json' | 'text' { const isBlobType = options.returnType?.toString().toLowerCase() === 'blob' || options.responseType?.toString().toLowerCase() === 'blob'; if (isBlobType) { @@ -358,8 +356,7 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { * @param returnType return type * @returns deserialized object */ - private static deserialize(response: HttpResponse, returnType?: Constructor | 'blob'): any { - + private deserialize(response: HttpResponse, returnType?: Constructor | 'blob'): any { if (response === null) { return null; } @@ -376,7 +373,7 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { } if (isBlobResponse(response, returnType)) { - return AdfHttpClient.deserializeBlobResponse(response); + return this.deserializeBlobResponse(response); } if (!isConstructor(returnType)) { @@ -390,9 +387,7 @@ export class AdfHttpClient implements ee.Emitter,JsApiHttpClient { return new returnType(body); } - - private static deserializeBlobResponse(response: HttpResponse) { - return new Blob([response.body], {type: response.headers.get('Content-Type')}); + private deserializeBlobResponse(response: HttpResponse) { + return new Blob([response.body], { type: response.headers.get('Content-Type') }); } } - diff --git a/lib/core/auth/src/index.ts b/lib/core/api/src/lib/tokens.ts similarity index 82% rename from lib/core/auth/src/index.ts rename to lib/core/api/src/lib/tokens.ts index f3aafc79242..57cdea70992 100644 --- a/lib/core/auth/src/index.ts +++ b/lib/core/api/src/lib/tokens.ts @@ -15,5 +15,6 @@ * limitations under the License. */ -export * from './authentication'; -export * from './authentication-interceptor/authentication.interceptor'; +import { HttpContextToken } from '@angular/common/http'; + +export const SHOULD_ADD_AUTH_TOKEN = new HttpContextToken(() => false); diff --git a/lib/core/auth/README.md b/lib/core/auth/README.md deleted file mode 100644 index a33492ea534..00000000000 --- a/lib/core/auth/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @alfresco/adf-core/auth - -Secondary entry point of `@alfresco/adf-core`. It can be used by importing from `@alfresco/adf-core/auth`. diff --git a/lib/core/auth/ng-package.json b/lib/core/auth/ng-package.json deleted file mode 100644 index c781f0df467..00000000000 --- a/lib/core/auth/ng-package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "lib": { - "entryFile": "src/index.ts" - } -} diff --git a/lib/core/auth/src/authentication-interceptor/README.md b/lib/core/auth/src/authentication-interceptor/README.md deleted file mode 100644 index 169e3a63a9d..00000000000 --- a/lib/core/auth/src/authentication-interceptor/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# AuthenticationInterceptor - -This interceptor is responsible for providing authentication to angular HttpClient requests when a context `SHOULD_ADD_AUTH_TOKEN` is set to true. -By default, the interceptor won't do anything to the intercepted request. - -## Usage - -```typescript -import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/auth'; -import { HttpClient, HttpContext } from '@angular/common/http'; - -getSth() { - return this.httpClient.get('http://example.com', { context: new HttpContext().set(SHOULD_ADD_AUTH_TOKEN, true)}); -} - -// or - -getSth() { - const someRequest = this.httpClient.get('GET', 'http://example.com'); - someRequest.context.set(SHOULD_ADD_AUTH_TOKEN, true); - - return someRequest; -} - -``` diff --git a/lib/core/auth/src/authentication-interceptor/authentication.interceptor.spec.ts b/lib/core/auth/src/authentication-interceptor/authentication.interceptor.spec.ts deleted file mode 100644 index 58af3fe8fff..00000000000 --- a/lib/core/auth/src/authentication-interceptor/authentication.interceptor.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * 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 { HttpHandler, HttpHeaders, HttpRequest } from '@angular/common/http'; -import { TestBed } from '@angular/core/testing'; -import { Observable, of } from 'rxjs'; -import { Authentication } from '../authentication'; -import { AuthenticationInterceptor, SHOULD_ADD_AUTH_TOKEN } from './authentication.interceptor'; - -class MockAuthentication extends Authentication { - addTokenToHeader(_: string, httpHeaders: HttpHeaders): Observable { - return of(httpHeaders); - } -} - -const mockNext: HttpHandler = { - handle: () => new Observable(subscriber => { - subscriber.complete(); - }) -}; - -const request = new HttpRequest('GET', 'http://localhost:4200'); - -describe('AuthenticationInterceptor', () => { - let interceptor: AuthenticationInterceptor; - let addTokenToHeaderSpy: jasmine.Spy; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [AuthenticationInterceptor, {provide: Authentication, useClass: MockAuthentication}] - }); - interceptor = TestBed.inject(AuthenticationInterceptor); - addTokenToHeaderSpy = spyOn(interceptor['authService'], 'addTokenToHeader'); - }); - - it('should call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to true', () => { - addTokenToHeaderSpy.and.callThrough(); - request.context.set(SHOULD_ADD_AUTH_TOKEN, true); - interceptor.intercept(request, mockNext); - expect(addTokenToHeaderSpy).toHaveBeenCalled(); - }); - - it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to false', () => { - request.context.set(SHOULD_ADD_AUTH_TOKEN, false); - interceptor.intercept(request, mockNext); - expect(addTokenToHeaderSpy).not.toHaveBeenCalled(); - }); - - it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is not provided', () => { - interceptor.intercept(request, mockNext); - expect(addTokenToHeaderSpy).not.toHaveBeenCalled(); - }); -}); diff --git a/lib/core/auth/src/authentication-interceptor/authentication.interceptor.ts b/lib/core/auth/src/authentication-interceptor/authentication.interceptor.ts deleted file mode 100644 index 6720e02ceb7..00000000000 --- a/lib/core/auth/src/authentication-interceptor/authentication.interceptor.ts +++ /dev/null @@ -1,77 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * 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 { - HttpContextToken, - HttpHandler, - HttpHeaderResponse, - HttpHeaders, - HttpInterceptor, - HttpProgressEvent, - HttpRequest, - HttpResponse, - HttpSentEvent, - HttpUserEvent -} from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable, throwError as observableThrowError } from 'rxjs'; -import { catchError, mergeMap } from 'rxjs/operators'; -import { Authentication } from '../authentication'; - -export const SHOULD_ADD_AUTH_TOKEN = new HttpContextToken(() => false); - -@Injectable() -export class AuthenticationInterceptor implements HttpInterceptor { - - constructor( private authService: Authentication) { } - - intercept(req: HttpRequest, next: HttpHandler): - Observable | HttpUserEvent> { - - if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) { - return this.authService.addTokenToHeader(req.url, req.headers).pipe( - mergeMap((headersWithBearer) => { - const headerWithContentType = this.appendJsonContentType(headersWithBearer); - const kcReq = req.clone({ headers: headerWithContentType}); - return next.handle(kcReq) - .pipe( - catchError((error) => observableThrowError(error)) - ); - }) - ); - } - - return next.handle(req).pipe(catchError((error) => observableThrowError(error))); - } - - private appendJsonContentType(headers: HttpHeaders): HttpHeaders { - - // prevent adding any content type, to properly handle formData with boundary browser generated value, - // as adding any Content-Type its going to break the upload functionality - - if (headers.get('Content-Type') === 'multipart/form-data') { - return headers.delete('Content-Type'); - } - - if (!headers.get('Content-Type')) { - return headers.set('Content-Type', 'application/json;charset=UTF-8'); - } - - return headers; - } - -} diff --git a/lib/core/index.ts b/lib/core/index.ts index 2cef37aee2b..e357b2379e6 100644 --- a/lib/core/index.ts +++ b/lib/core/index.ts @@ -16,4 +16,3 @@ */ export * from './src/public-api'; -export * from './api/src/index'; diff --git a/lib/core/src/lib/app-config/app-config.loader.ts b/lib/core/src/lib/app-config/app-config.loader.ts index 1744729a593..f8acf01fc07 100644 --- a/lib/core/src/lib/app-config/app-config.loader.ts +++ b/lib/core/src/lib/app-config/app-config.loader.ts @@ -34,8 +34,7 @@ export function loadAppConfig( storageService: StorageService, adfHttpClient: AdfHttpClient, storagePrefixFactory: StoragePrefixFactory - ) { - +) { const init = () => { adfHttpClient.disableCsrf = appConfigService.get(AppConfigValues.DISABLECSRF, true); storageService.prefix = appConfigService.get(AppConfigValues.STORAGE_PREFIX, ''); @@ -45,4 +44,4 @@ export function loadAppConfig( }); }; return () => appConfigService.load(init); -}; +} diff --git a/lib/core/src/lib/app-config/app-config.service.ts b/lib/core/src/lib/app-config/app-config.service.ts index a2343d9b5c4..a85bedfbe1d 100644 --- a/lib/core/src/lib/app-config/app-config.service.ts +++ b/lib/core/src/lib/app-config/app-config.service.ts @@ -76,17 +76,14 @@ export class AppConfigService { }; status: Status = Status.INIT; - protected onLoadSubject: ReplaySubject; - onLoad: Observable; + protected readonly onLoadSubject = new ReplaySubject(); + onLoad = this.onLoadSubject.asObservable(); get isLoaded() { return this.status === Status.LOADED; } constructor() { - this.onLoadSubject = new ReplaySubject(); - this.onLoad = this.onLoadSubject.asObservable(); - this.extensionService.setup$.subscribe((config) => { this.onExtensionsLoaded(config); }); diff --git a/lib/core/src/lib/app-config/debug-app-config.service.ts b/lib/core/src/lib/app-config/debug-app-config.service.ts deleted file mode 100644 index 56ace1ab364..00000000000 --- a/lib/core/src/lib/app-config/debug-app-config.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * 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 { StorageService } from '../common/services/storage.service'; -import { AppConfigService, AppConfigValues } from './app-config.service'; - -@Injectable() -export class DebugAppConfigService extends AppConfigService { - constructor(private storage: StorageService) { - super(); - } - - /** @override */ - get(key: string, defaultValue?: T): T { - if (key === AppConfigValues.OAUTHCONFIG) { - return JSON.parse(this.storage.getItem(key)) || super.get(key, defaultValue); - } else if (key === AppConfigValues.APPLICATION) { - return undefined; - } else { - return (this.storage.getItem(key) as any) || super.get(key, defaultValue); - } - } -} diff --git a/lib/core/src/lib/app-config/public-api.ts b/lib/core/src/lib/app-config/public-api.ts index b98f2ecdc22..0048b8563ad 100644 --- a/lib/core/src/lib/app-config/public-api.ts +++ b/lib/core/src/lib/app-config/public-api.ts @@ -16,7 +16,6 @@ */ export * from './app-config.service'; -export * from './debug-app-config.service'; export * from './app-config.pipe'; export * from './app-config-storage-prefix.factory'; diff --git a/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.spec.ts b/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.spec.ts new file mode 100644 index 00000000000..989d2002596 --- /dev/null +++ b/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.spec.ts @@ -0,0 +1,69 @@ +/*! + * @license + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { HttpHandler, HttpHeaders, HttpRequest } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { Observable, of } from 'rxjs'; +import { Authentication } from '../authentication'; +import { AuthenticationInterceptor } from './authentication.interceptor'; +import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/api'; + +class MockAuthentication extends Authentication { + addTokenToHeader(_: string, httpHeaders: HttpHeaders): Observable { + return of(httpHeaders); + } +} + +const mockNext: HttpHandler = { + handle: () => + new Observable((subscriber) => { + subscriber.complete(); + }) +}; + +const request = new HttpRequest('GET', 'http://localhost:4200'); + +describe('AuthenticationInterceptor', () => { + let interceptor: AuthenticationInterceptor; + let addTokenToHeaderSpy: jasmine.Spy; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AuthenticationInterceptor, { provide: Authentication, useClass: MockAuthentication }] + }); + interceptor = TestBed.inject(AuthenticationInterceptor); + addTokenToHeaderSpy = spyOn(interceptor['authService'], 'addTokenToHeader'); + }); + + it('should call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to true', () => { + addTokenToHeaderSpy.and.callThrough(); + request.context.set(SHOULD_ADD_AUTH_TOKEN, true); + interceptor.intercept(request, mockNext); + expect(addTokenToHeaderSpy).toHaveBeenCalled(); + }); + + it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to false', () => { + request.context.set(SHOULD_ADD_AUTH_TOKEN, false); + interceptor.intercept(request, mockNext); + expect(addTokenToHeaderSpy).not.toHaveBeenCalled(); + }); + + it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is not provided', () => { + interceptor.intercept(request, mockNext); + expect(addTokenToHeaderSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.ts b/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.ts new file mode 100644 index 00000000000..7e6093ae924 --- /dev/null +++ b/lib/core/src/lib/auth/authentication-interceptor/authentication.interceptor.ts @@ -0,0 +1,70 @@ +/*! + * @license + * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { + HttpHandler, + HttpHeaderResponse, + HttpHeaders, + HttpInterceptor, + HttpProgressEvent, + HttpRequest, + HttpResponse, + HttpSentEvent, + HttpUserEvent +} from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, throwError as observableThrowError } from 'rxjs'; +import { catchError, mergeMap } from 'rxjs/operators'; +import { Authentication } from '../authentication'; +import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/api'; + +@Injectable() +export class AuthenticationInterceptor implements HttpInterceptor { + constructor(private authService: Authentication) {} + + intercept( + req: HttpRequest, + next: HttpHandler + ): Observable | HttpUserEvent> { + if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) { + return this.authService.addTokenToHeader(req.url, req.headers).pipe( + mergeMap((headersWithBearer) => { + const headerWithContentType = this.appendJsonContentType(headersWithBearer); + const kcReq = req.clone({ headers: headerWithContentType }); + return next.handle(kcReq).pipe(catchError((error) => observableThrowError(error))); + }) + ); + } + + return next.handle(req).pipe(catchError((error) => observableThrowError(error))); + } + + private appendJsonContentType(headers: HttpHeaders): HttpHeaders { + // prevent adding any content type, to properly handle formData with boundary browser generated value, + // as adding any Content-Type its going to break the upload functionality + + if (headers.get('Content-Type') === 'multipart/form-data') { + return headers.delete('Content-Type'); + } + + if (!headers.get('Content-Type')) { + return headers.set('Content-Type', 'application/json;charset=UTF-8'); + } + + return headers; + } +} diff --git a/lib/core/auth/src/authentication.ts b/lib/core/src/lib/auth/authentication.ts similarity index 100% rename from lib/core/auth/src/authentication.ts rename to lib/core/src/lib/auth/authentication.ts diff --git a/lib/core/src/lib/auth/public-api.ts b/lib/core/src/lib/auth/public-api.ts index a457bd9530b..82cafe4e230 100644 --- a/lib/core/src/lib/auth/public-api.ts +++ b/lib/core/src/lib/auth/public-api.ts @@ -15,8 +15,9 @@ * limitations under the License. */ +export * from './authentication'; export * from './authentication-interceptor/auth-bearer.interceptor'; - +export * from './authentication-interceptor/authentication.interceptor'; export * from './guard/auth-guard.service'; export * from './guard/auth-guard'; export * from './guard/auth-guard-ecm.service'; diff --git a/lib/core/src/lib/core.module.ts b/lib/core/src/lib/core.module.ts index fcc5acac556..137dba16e55 100644 --- a/lib/core/src/lib/core.module.ts +++ b/lib/core/src/lib/core.module.ts @@ -41,7 +41,7 @@ import { TranslationService } from './translation/translation.service'; import { TranslateLoaderService } from './translation/translate-loader.service'; import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module'; import { AdfHttpClient } from '@alfresco/adf-core/api'; -import { AuthenticationInterceptor, Authentication } from '@alfresco/adf-core/auth'; +import { AuthenticationInterceptor, Authentication } from './auth'; import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthenticationService } from './auth/services/authentication.service'; import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar'; diff --git a/lib/core/tsconfig.lib.json b/lib/core/tsconfig.lib.json index 52354392976..895019b1709 100644 --- a/lib/core/tsconfig.lib.json +++ b/lib/core/tsconfig.lib.json @@ -7,7 +7,6 @@ "paths": { "@alfresco/adf-extensions": ["../../../dist/libs/extensions"], "@alfresco/adf-extensions/*": ["../../../dist/libs/extensions/*"], - "@alfresco/adf-core/auth": ["../auth/src/index.ts"], "@alfresco/adf-core/shell": ["../shell/src/index.ts"], "@alfresco/adf-core/api": ["../api/src/index.ts"], "@alfresco/adf-core/feature-flags": ["../feature-flags/src/index.ts"], diff --git a/lib/insights/src/lib/testing/insights.testing.module.ts b/lib/insights/src/lib/testing/insights.testing.module.ts index ab4fa461f22..9c35279abc0 100644 --- a/lib/insights/src/lib/testing/insights.testing.module.ts +++ b/lib/insights/src/lib/testing/insights.testing.module.ts @@ -17,19 +17,17 @@ import { NgModule } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { - AppConfigService, - AppConfigServiceMock, - AuthModule, - NoopTranslateModule -} from '@alfresco/adf-core'; +import { AppConfigService, AppConfigServiceMock, AuthModule, NoopTranslateModule } from '@alfresco/adf-core'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; @NgModule({ imports: [AuthModule.forRoot({ useHash: true }), NoopAnimationsModule, NoopTranslateModule], providers: [ { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, - { provide: AppConfigService, useClass: AppConfigServiceMock } + { provide: AppConfigService, useClass: AppConfigServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } ], exports: [NoopAnimationsModule] }) diff --git a/lib/process-services/src/lib/attachment/create-process-attachment/create-process-attachment.component.spec.ts b/lib/process-services/src/lib/attachment/create-process-attachment/create-process-attachment.component.spec.ts index 334e50b3aa5..4f3a39d6fdd 100644 --- a/lib/process-services/src/lib/attachment/create-process-attachment/create-process-attachment.component.spec.ts +++ b/lib/process-services/src/lib/attachment/create-process-attachment/create-process-attachment.component.spec.ts @@ -20,6 +20,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CreateProcessAttachmentComponent } from './create-process-attachment.component'; import { ProcessTestingModule } from '../../testing/process.testing.module'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -49,7 +50,11 @@ describe('CreateProcessAttachmentComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ProcessTestingModule, CreateProcessAttachmentComponent], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); fixture = TestBed.createComponent(CreateProcessAttachmentComponent); component = fixture.componentInstance; diff --git a/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts b/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts index ee674bbb637..f8afe4248c9 100644 --- a/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts +++ b/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts @@ -20,6 +20,7 @@ import { FormModel, CoreTestingModule } from '@alfresco/adf-core'; import { EcmModelService } from './ecm-model.service'; import { TestBed } from '@angular/core/testing'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -29,7 +30,11 @@ describe('EcmModelService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); service = TestBed.inject(EcmModelService); jasmine.Ajax.install(); diff --git a/lib/process-services/src/lib/form/services/process-content.service.spec.ts b/lib/process-services/src/lib/form/services/process-content.service.spec.ts index 3aa0fc1238d..0d840c28d0a 100644 --- a/lib/process-services/src/lib/form/services/process-content.service.spec.ts +++ b/lib/process-services/src/lib/form/services/process-content.service.spec.ts @@ -20,6 +20,7 @@ import { of } from 'rxjs'; import { ProcessContentService } from './process-content.service'; import { CoreTestingModule } from '@alfresco/adf-core'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -68,7 +69,11 @@ describe('ProcessContentService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); service = TestBed.inject(ProcessContentService); }); diff --git a/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts b/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts index 6e5573ba0cc..ff8649da2b1 100644 --- a/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts @@ -23,6 +23,7 @@ import { of } from 'rxjs'; import { ContentWidgetComponent } from './content.widget'; import { ProcessContentService } from '../../services/process-content.service'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -61,7 +62,11 @@ describe('ContentWidgetComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule, ContentWidgetComponent], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); downloadService = TestBed.inject(DownloadService); processContentService = TestBed.inject(ProcessContentService); diff --git a/lib/process-services/src/lib/people/components/people-search/people-search.component.spec.ts b/lib/process-services/src/lib/people/components/people-search/people-search.component.spec.ts index af421441f19..a57a24fbc32 100644 --- a/lib/process-services/src/lib/people/components/people-search/people-search.component.spec.ts +++ b/lib/process-services/src/lib/people/components/people-search/people-search.component.spec.ts @@ -20,6 +20,7 @@ import { of } from 'rxjs'; import { PeopleSearchComponent } from './people-search.component'; import { ProcessTestingModule } from '../../../testing/process.testing.module'; import { LightUserRepresentation } from '@alfresco/js-api'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; const fakeUser: LightUserRepresentation = { id: 1, @@ -44,7 +45,11 @@ describe('PeopleSearchComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ProcessTestingModule, PeopleSearchComponent] + imports: [ProcessTestingModule, PeopleSearchComponent], + providers: [ + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); fixture = TestBed.createComponent(PeopleSearchComponent); peopleSearchComponent = fixture.componentInstance; diff --git a/lib/process-services/src/lib/people/components/people/people.component.spec.ts b/lib/process-services/src/lib/people/components/people/people.component.spec.ts index 12cf893d497..efc7ffd364a 100644 --- a/lib/process-services/src/lib/people/components/people/people.component.spec.ts +++ b/lib/process-services/src/lib/people/components/people/people.component.spec.ts @@ -19,8 +19,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PeopleComponent } from './people.component'; import { ProcessTestingModule } from '../../../testing/process.testing.module'; import { LightUserRepresentation } from '@alfresco/js-api'; -import { PeopleProcessService } from '@alfresco/adf-process-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; import { of, throwError } from 'rxjs'; +import { PeopleProcessService } from '@alfresco/adf-process-services'; const fakeUser: LightUserRepresentation = { id: 0, @@ -45,7 +46,11 @@ describe('PeopleComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ProcessTestingModule, PeopleComponent] + imports: [ProcessTestingModule, PeopleComponent], + providers: [ + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); fixture = TestBed.createComponent(PeopleComponent); peopleProcessService = fixture.debugElement.injector.get(PeopleProcessService); diff --git a/lib/process-services/src/lib/process-list/services/process-filter.service.spec.ts b/lib/process-services/src/lib/process-list/services/process-filter.service.spec.ts index d3934dd9bf2..2c27bdee9b3 100644 --- a/lib/process-services/src/lib/process-list/services/process-filter.service.spec.ts +++ b/lib/process-services/src/lib/process-list/services/process-filter.service.spec.ts @@ -21,6 +21,7 @@ import { CoreTestingModule } from '@alfresco/adf-core'; import { ProcessInstanceFilterRepresentation, UserProcessInstanceFilterRepresentation } from '@alfresco/js-api'; import { of } from 'rxjs'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -51,7 +52,11 @@ describe('Process filter', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); service = TestBed.inject(ProcessFilterService); }); diff --git a/lib/process-services/src/lib/services/people-process.service.spec.ts b/lib/process-services/src/lib/services/people-process.service.spec.ts index 03c35b91470..b29898fb039 100644 --- a/lib/process-services/src/lib/services/people-process.service.spec.ts +++ b/lib/process-services/src/lib/services/people-process.service.spec.ts @@ -20,6 +20,7 @@ import { PeopleProcessService } from './people-process.service'; import { CoreTestingModule } from '@alfresco/adf-core'; import { LightUserRepresentation } from '@alfresco/js-api'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -47,7 +48,11 @@ describe('PeopleProcessService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule], - providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } + ] }); service = TestBed.inject(PeopleProcessService); }); diff --git a/lib/process-services/src/lib/task-list/components/task-list/task-list.component.spec.ts b/lib/process-services/src/lib/task-list/components/task-list/task-list.component.spec.ts index f34b374fa82..b7e6aec5d4a 100644 --- a/lib/process-services/src/lib/task-list/components/task-list/task-list.component.spec.ts +++ b/lib/process-services/src/lib/task-list/components/task-list/task-list.component.spec.ts @@ -44,6 +44,7 @@ import { MatMenuItemHarness } from '@angular/material/menu/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; import { CommonModule } from '@angular/common'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; declare let jasmine: any; @@ -112,7 +113,9 @@ describe('TaskListComponent', () => { providers: [ TaskListService, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, - { provide: AppConfigService, useClass: AppConfigServiceMock } + { provide: AppConfigService, useClass: AppConfigServiceMock }, + // TODO: remove this as soon as unit test not using jasmine.Ajax + { provide: AdfHttpClient, useValue: null } ] }); appConfig = TestBed.inject(AppConfigService); diff --git a/tsconfig.json b/tsconfig.json index d8ecf9dbb38..cb12c78f2a0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,6 @@ "@alfresco/adf-core": ["lib/core/src/public-api.ts"], "@alfresco/adf-core/*": ["lib/core/*/public-api.ts"], "@alfresco/adf-core/api": ["lib/core/api/src/index.ts"], - "@alfresco/adf-core/auth": ["lib/core/auth/src/index.ts"], "@alfresco/adf-core/breadcrumbs": ["lib/core/breadcrumbs/src/index.ts"], "@alfresco/adf-core/feature-flags": ["lib/core/feature-flags/src/index.ts"], "@alfresco/adf-core/shell": ["lib/core/shell/src/index.ts"],