]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/services/api-interceptor.service.ts
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / services / api-interceptor.service.ts
1 import {
2 HttpErrorResponse,
3 HttpEvent,
4 HttpHandler,
5 HttpInterceptor,
6 HttpRequest
7 } from '@angular/common/http';
8 import { Injectable } from '@angular/core';
9 import { Router } from '@angular/router';
10
11 import _ from 'lodash';
12 import { Observable, throwError as observableThrowError } from 'rxjs';
13 import { catchError } from 'rxjs/operators';
14
15 import { CdHelperClass } from '~/app/shared/classes/cd-helper.class';
16 import { NotificationType } from '../enum/notification-type.enum';
17 import { CdNotificationConfig } from '../models/cd-notification';
18 import { FinishedTask } from '../models/finished-task';
19 import { AuthStorageService } from './auth-storage.service';
20 import { NotificationService } from './notification.service';
21
22 export class CdHttpErrorResponse extends HttpErrorResponse {
23 preventDefault: Function;
24 ignoreStatusCode: Function;
25 }
26
27 @Injectable({
28 providedIn: 'root'
29 })
30 export class ApiInterceptorService implements HttpInterceptor {
31 constructor(
32 private router: Router,
33 private authStorageService: AuthStorageService,
34 public notificationService: NotificationService
35 ) {}
36
37 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
38 const acceptHeader = request.headers.get('Accept');
39 let reqWithVersion: HttpRequest<any>;
40 if (acceptHeader && acceptHeader.startsWith('application/vnd.ceph.api.v')) {
41 reqWithVersion = request.clone();
42 } else {
43 reqWithVersion = request.clone({
44 setHeaders: {
45 Accept: CdHelperClass.cdVersionHeader('1', '0')
46 }
47 });
48 }
49 return next.handle(reqWithVersion).pipe(
50 catchError((resp: CdHttpErrorResponse) => {
51 if (resp instanceof HttpErrorResponse) {
52 let timeoutId: number;
53 switch (resp.status) {
54 case 400:
55 const finishedTask = new FinishedTask();
56
57 const task = resp.error.task;
58 if (_.isPlainObject(task)) {
59 task.metadata.component = task.metadata.component || resp.error.component;
60
61 finishedTask.name = task.name;
62 finishedTask.metadata = task.metadata;
63 } else {
64 finishedTask.metadata = resp.error;
65 }
66
67 finishedTask.success = false;
68 finishedTask.exception = resp.error;
69 timeoutId = this.notificationService.notifyTask(finishedTask);
70 break;
71 case 401:
72 this.authStorageService.remove();
73 this.router.navigate(['/login']);
74 break;
75 case 403:
76 this.router.navigate(['error'], {
77 state: {
78 message: $localize`Sorry, you don’t have permission to view this page or resource.`,
79 header: $localize`Access Denied`,
80 icon: 'fa fa-lock',
81 source: 'forbidden'
82 }
83 });
84 break;
85 default:
86 timeoutId = this.prepareNotification(resp);
87 }
88
89 /**
90 * Decorated preventDefault method (in case error previously had
91 * preventDefault method defined). If called, it will prevent a
92 * notification to be shown.
93 */
94 resp.preventDefault = () => {
95 this.notificationService.cancel(timeoutId);
96 };
97
98 /**
99 * If called, it will prevent a notification for the specific status code.
100 * @param {number} status The status code to be ignored.
101 */
102 resp.ignoreStatusCode = function (status: number) {
103 if (this.status === status) {
104 this.preventDefault();
105 }
106 };
107 }
108 // Return the error to the method that called it.
109 return observableThrowError(resp);
110 })
111 );
112 }
113
114 private prepareNotification(resp: any): number {
115 return this.notificationService.show(() => {
116 let message = '';
117 if (_.isPlainObject(resp.error) && _.isString(resp.error.detail)) {
118 message = resp.error.detail; // Error was triggered by the backend.
119 } else if (_.isString(resp.error)) {
120 message = resp.error;
121 } else if (_.isString(resp.message)) {
122 message = resp.message;
123 }
124 return new CdNotificationConfig(
125 NotificationType.error,
126 `${resp.status} - ${resp.statusText}`,
127 message,
128 undefined,
129 resp['application']
130 );
131 });
132 }
133 }