| /******************************************************************************** |
| * 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})); |
| }); |
| } |