blob: f7d44a75fddf94fea14a6eb81c705ef6f36b7dbc [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {HttpErrorResponse, HttpResponse} from "@angular/common/http";
import {Observable, ObservableInput, of, throwError} from "rxjs";
import {catchError, switchMap} from "rxjs/operators";
import {arrayJoin} from "../store";
import {EHttpStatusCodes} from "./EHttpStatusCodes";
/**
* Safely joins multiple urls to one.
*/
export function urlJoin(...args: string[]): string {
let result = args.length === 0 ? "" : args.reduce((previous, current) => previous + "/" + current);
const indexOfProtocol = result.indexOf("://");
const protocol = indexOfProtocol === -1 ? "" : result.slice(0, indexOfProtocol);
result = indexOfProtocol === -1 ? result : result.slice(indexOfProtocol + 2);
while (result.indexOf("//") > -1) {
result = result.replace("//", "/");
}
return indexOfProtocol === -1 ? result : protocol + ":/" + result;
}
/**
* Transforms a javascript object to a HttpParams object.
*/
export function objectToHttpParams<T extends object>(
object: { [key: string]: string | number | Array<string | number> }
): { [key: string]: string | string[] } {
if (object == null) {
return {};
}
const result: { [key: string]: string | string[] } = {};
Object.entries(object)
.filter(([key, value]) => value != null)
.forEach(([key, value]) => {
result[key] = Array.isArray(value) ? value.map((_) => "" + _) : "" + value;
});
return result;
}
/**
* Returns true if the given error is an instance of HttpErrorResponse and its status is contained in the
* given list of status values of the function (if empty, all status values are catched).
*/
export function isHttpErrorWithStatus(error: any, ...status: EHttpStatusCodes[]): boolean {
return error instanceof HttpErrorResponse
&& (arrayJoin(status).length === 0 || status.some((s) => error.status === s));
}
/**
* Returns an rxjs operator which catches HttpErrorRespones.
* @param callback Function which is called when an error occurs.
* @param status List of all response status codes which are catched (if empty, all http errors are catched).
*/
export function catchHttpError<T, O extends ObservableInput<any>>(
callback: (error: HttpErrorResponse) => O,
...status: EHttpStatusCodes[]
) {
return catchError<T, O | Observable<never>>((error) => {
if (isHttpErrorWithStatus(error, ...arrayJoin(status))) {
return callback(error);
}
return throwError(error);
});
}
/**
* Returns an rxjs operator which catches every http error and maps it to the given value.
* @param value Value, to which an http error is mapped to.
* @param status List of all response status codes which are catched (if empty, all http errors are catched).
*/
export function catchHttpErrorTo<T, O>(
value: O,
...status: EHttpStatusCodes[]
) {
return catchHttpError<T, ObservableInput<O>>(() => of(value), ...status);
}
/**
* Returns an rxjs operator function which maps a HttpResponse from the server to a Javascript file object.
* The filename of the returned file will be extracted from the headers of the HttpResponse.
*/
export function mapHttpResponseToFile() {
return switchMap<HttpResponse<Blob>, Observable<File>>((response) => {
const blob = response.body;
if (!(blob instanceof Blob)) {
return throwError(new TypeError("Http response does not contain blob data"));
}
const contentDisposition = response.headers.get("content-disposition");
const fileName = contentDisposition
.split(";")
.map((_) => {
_ = _.trim();
if (!_.toLowerCase().startsWith("filename=")) {
return;
}
return _.slice(9)
.replace(/^\s*"/, "")
.replace(/"\s*$/, "");
})
.find((_) => _ != null);
return of(new File([blob], fileName, {type: blob.type}));
});
}