Skip to content

Commit e1ca565

Browse files
authored
[MULTIDIRECTORY-771] Error handling: interceptor + dictionary
1 parent e81ca89 commit e1ca565

File tree

19 files changed

+306
-272
lines changed

19 files changed

+306
-272
lines changed

projects/multidirectory-app/src/app/app.config.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { DEFAULT_DIALOG_CONFIG } from '@angular/cdk/dialog';
22
import { DragDropModule } from '@angular/cdk/drag-drop';
33
import { OverlayContainer } from '@angular/cdk/overlay';
4-
import {
5-
HTTP_INTERCEPTORS,
6-
HttpClient,
7-
provideHttpClient,
8-
withInterceptorsFromDi,
9-
} from '@angular/common/http';
4+
import { HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
105
import {
116
ApplicationConfig,
127
ErrorHandler,
@@ -23,7 +18,6 @@ import { ApiAdapter } from '@core/api/api-adapter';
2318
import { DnsAdapterSettings } from '@core/api/dns-adapter.settings';
2419
import { GlobalErrorHandler } from '@core/api/error-handling/global-error-handler';
2520
import { PasswordPolicyViolationInterceptor } from '@core/api/error-handling/password-policy-violation-interceptor';
26-
import { ResultCodeInterceptor } from '@core/api/error-handling/result-code-interceptor';
2721
import { MultidirectoryAdapterSettings } from '@core/api/multidirectory-adapter.settings';
2822
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
2923
import { provideTransloco, TranslocoService } from '@jsverse/transloco';
@@ -36,6 +30,7 @@ import { environment } from '../environments/environment';
3630
import { appRoutes } from './app.routes';
3731
import { DIALOG_CONFIG_DEFAULT } from './components/modals/constants/dialog.constants';
3832
import { TranslocoHttpLoader } from './transloco-loader';
33+
import { ErrorInterceptor } from '@core/interceptors/error.interceptor';
3934

4035
export const appConfig: ApplicationConfig = {
4136
providers: [
@@ -54,20 +49,11 @@ export const appConfig: ApplicationConfig = {
5449
{
5550
provide: 'apiAdapter',
5651
useFactory: () =>
57-
new ApiAdapter<MultidirectoryAdapterSettings>(
58-
inject(HttpClient),
59-
inject(MultidirectoryAdapterSettings),
60-
inject(ToastrService),
61-
),
52+
new ApiAdapter<MultidirectoryAdapterSettings>(inject(HttpClient), inject(MultidirectoryAdapterSettings), inject(ToastrService)),
6253
},
6354
{
6455
provide: 'dnsAdapter',
65-
useFactory: () =>
66-
new ApiAdapter<DnsAdapterSettings>(
67-
inject(HttpClient),
68-
inject(DnsAdapterSettings),
69-
inject(ToastrService),
70-
),
56+
useFactory: () => new ApiAdapter<DnsAdapterSettings>(inject(HttpClient), inject(DnsAdapterSettings), inject(ToastrService)),
7157
},
7258
{
7359
provide: ErrorHandler,
@@ -76,7 +62,7 @@ export const appConfig: ApplicationConfig = {
7662
provideHttpClient(withInterceptorsFromDi()),
7763
{
7864
provide: HTTP_INTERCEPTORS,
79-
useClass: ResultCodeInterceptor,
65+
useClass: ErrorInterceptor,
8066
multi: true,
8167
},
8268
{

projects/multidirectory-app/src/app/components/app-layout/app-layout.component.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
7979
const nameAttirbute = searchEntry.partial_attributes.find((x) => x.type == 'name');
8080
const displayName = nameAttirbute?.vals?.[0] ?? '';
8181

82-
const objectClass = searchEntry.partial_attributes.find(
83-
(x) => x.type.toLocaleLowerCase() == 'objectclass',
84-
)!;
82+
const objectClass = searchEntry.partial_attributes.find((x) => x.type.toLocaleLowerCase() == 'objectclass')!;
8583
const entry = new NavigationNode({
8684
name: displayName,
8785
selectable: true,
@@ -100,7 +98,6 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
10098
.status()
10199
.pipe(
102100
catchError(() => {
103-
this.toastr.error(translate('dns-settings.dns-unavailable'));
104101
return of(
105102
new DnsStatusResponse({
106103
dns_status: DnsStatuses.NOT_CONFIGURED,

projects/multidirectory-app/src/app/components/modals/components/dialogs/add-principal-dialog/add-principal-dialog.component.ts

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
ChangeDetectionStrategy,
3-
Component,
4-
DestroyRef,
5-
inject,
6-
OnInit,
7-
ViewChild,
8-
} from '@angular/core';
1+
import { ChangeDetectionStrategy, Component, DestroyRef, inject, OnInit, ViewChild } from '@angular/core';
92
import { DialogComponent } from '../../core/dialog/dialog.component';
103
import { MdFormComponent, MultidirectoryUiKitModule } from 'multidirectory-ui-kit';
114
import { PatternWithMessageDirective } from '@core/validators/pattern-with-message.directive';
@@ -44,8 +37,7 @@ export class AddPrincipalDialogComponent implements OnInit {
4437
principalName = '';
4538

4639
private dialogService: DialogService = inject(DialogService);
47-
private dialogRef: DialogRef<AddPrincipalDialogReturnData, AddPrincipalDialogComponent> =
48-
inject(DialogRef);
40+
private dialogRef: DialogRef<AddPrincipalDialogReturnData, AddPrincipalDialogComponent> = inject(DialogRef);
4941
private api: MultidirectoryApiService = inject(MultidirectoryApiService);
5042
private toastr: ToastrService = inject(ToastrService);
5143
private destroyRef$: DestroyRef = inject(DestroyRef);
@@ -64,20 +56,10 @@ export class AddPrincipalDialogComponent implements OnInit {
6456
this.dialogComponent.showSpinner();
6557
const request = new AddPrincipalRequest(this.principalName);
6658

67-
this.api
68-
.addPrincipal(request)
69-
.pipe(
70-
catchError(() => {
71-
this.toastr.error(translate('add-principal.unable-to-add'));
72-
this.dialogComponent.hideSpinner();
73-
74-
return EMPTY;
75-
}),
76-
)
77-
.subscribe((x) => {
78-
this.dialogComponent.hideSpinner();
79-
this.dialogService.close(this.dialogRef, x);
80-
});
59+
this.api.addPrincipal(request).subscribe((x) => {
60+
this.dialogComponent.hideSpinner();
61+
this.dialogService.close(this.dialogRef, x);
62+
});
8163
}
8264

8365
onClose() {

projects/multidirectory-app/src/app/components/modals/components/dialogs/change-password-dialog/change-password-dialog.component.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,11 @@ export class ChangePasswordDialogComponent {
7373

7474
protected finish() {
7575
this.dialog().showSpinner();
76-
this.api
77-
.changePassword(this.changeRequest)
78-
.pipe(
79-
catchError(() => {
80-
this.toastr.error(translate('change-password.unable-change-password'));
81-
this.dialogService.close(this.dialogRef);
82-
this.dialog().hideSpinner();
83-
return EMPTY;
84-
}),
85-
)
86-
.subscribe((x) => {
87-
this.toastr.success(translate('change-password.password-successfully-changed'));
88-
this.dialog().hideSpinner();
89-
this.dialogService.close(this.dialogRef, x);
90-
});
76+
this.api.changePassword(this.changeRequest).subscribe((x) => {
77+
this.toastr.success(translate('change-password.password-successfully-changed'));
78+
this.dialog().hideSpinner();
79+
this.dialogService.close(this.dialogRef, x);
80+
});
9181
}
9282

9383
protected checkModel() {

projects/multidirectory-app/src/app/components/modals/components/dialogs/create-group-dialog/create-group-dialog.component.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import { FormsModule } from '@angular/forms';
77
import { catchError, EMPTY, map, Observable, Subject, switchMap, takeUntil } from 'rxjs';
88
import { DialogService } from '../../../services/dialog.service';
99
import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
10-
import {
11-
CreateGroupDialogData,
12-
CreateGroupDialogReturnData,
13-
} from '../../../interfaces/create-group-dialog.interface';
10+
import { CreateGroupDialogData, CreateGroupDialogReturnData } from '../../../interfaces/create-group-dialog.interface';
1411
import { MultidirectoryApiService } from '@services/multidirectory-api.service';
1512
import { ToastrService } from 'ngx-toastr';
1613
import { LdapAttribute } from '@core/ldap/ldap-attributes/ldap-attribute';
@@ -21,14 +18,7 @@ import { SchemaService } from '@services/schema/schema.service';
2118
@Component({
2219
selector: 'app-create-group-dialog',
2320
standalone: true,
24-
imports: [
25-
DialogComponent,
26-
MultidirectoryUiKitModule,
27-
RequiredWithMessageDirective,
28-
TranslocoDirective,
29-
FormsModule,
30-
TranslocoPipe,
31-
],
21+
imports: [DialogComponent, MultidirectoryUiKitModule, RequiredWithMessageDirective, TranslocoDirective, FormsModule, TranslocoPipe],
3222
templateUrl: './create-group-dialog.component.html',
3323
styleUrl: './create-group-dialog.component.scss',
3424
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -39,8 +29,7 @@ export class CreateGroupDialogComponent implements OnInit {
3929
formValid = false;
4030

4131
private dialogService: DialogService = inject(DialogService);
42-
private dialogRef: DialogRef<CreateGroupDialogReturnData, CreateGroupDialogComponent> =
43-
inject(DialogRef);
32+
private dialogRef: DialogRef<CreateGroupDialogReturnData, CreateGroupDialogComponent> = inject(DialogRef);
4433
private api: MultidirectoryApiService = inject(MultidirectoryApiService);
4534
private toastr: ToastrService = inject(ToastrService);
4635
private schema = inject(SchemaService);
@@ -100,8 +89,6 @@ export class CreateGroupDialogComponent implements OnInit {
10089
);
10190
}),
10291
catchError(() => {
103-
this.dialogComponent?.hideSpinner();
104-
this.toastr.error(translate('group-create.unable-create-group'));
10592
this.dialogService.close(this.dialogRef);
10693
return EMPTY;
10794
}),

projects/multidirectory-app/src/app/core/api/error-handling/global-error-handler.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,17 @@ export class GlobalErrorHandler implements ErrorHandler {
1717
}
1818

1919
handleError(error: any) {
20-
console.error(error);
2120
if (error.error instanceof ProgressEvent) {
2221
this.router.navigate(['/enable-backend']);
2322
return;
2423
}
2524

2625
if (error.error?.detail) {
27-
if (typeof error.error?.detail === 'string' || error.error?.detail instanceof String) {
28-
this.toastr.error(error.error.detail);
26+
if (error.status == 451) {
27+
this.toastr.error(translate('errors.license-problem'));
2928
return;
3029
}
31-
32-
for (const i of error.error.detail) {
33-
this.toastr.error(i?.msg ?? i);
34-
}
3530
return;
3631
}
37-
this.toastr.error(error?.statusText ?? translate('errors.unknown-error'), '', {
38-
onActivateTick: true,
39-
});
4032
}
4133
}

projects/multidirectory-app/src/app/core/api/error-handling/result-code-interceptor.ts

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
2+
import { inject, Injectable } from '@angular/core';
3+
import { Router } from '@angular/router';
4+
import { NgxSpinnerService } from 'ngx-spinner';
5+
import { ToastrService } from 'ngx-toastr';
6+
import { catchError, EMPTY, Observable, take, throwError } from 'rxjs';
7+
import { AppSettingsService } from '@services/app-settings.service';
8+
import { DialogService } from '@components/modals/services/dialog.service';
9+
import { translate } from '@jsverse/transloco';
10+
export const ErrorCode = {
11+
BadRequest: 400,
12+
NotAuthorized: 401,
13+
UnprocessableEntity: 422,
14+
NotFound: 404,
15+
InternalServerError: 500,
16+
};
17+
@Injectable()
18+
export class ErrorInterceptor implements HttpInterceptor {
19+
private readonly toastr = inject(ToastrService);
20+
private readonly spinner = inject(NgxSpinnerService);
21+
private readonly router = inject(Router);
22+
private app: AppSettingsService = inject(AppSettingsService);
23+
private dialogService = inject(DialogService);
24+
25+
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
26+
return next.handle(req).pipe(
27+
catchError((error: HttpErrorResponse) => {
28+
this.spinner.hide();
29+
if (error.status === ErrorCode.NotAuthorized) {
30+
const errText = this.parseBadRequestError(error);
31+
this.toastr.info(errText);
32+
this.dialogService.closeAll();
33+
34+
return throwError(() => error);
35+
}
36+
if (
37+
error.status === ErrorCode.BadRequest ||
38+
error.status === ErrorCode.InternalServerError ||
39+
error.status === ErrorCode.UnprocessableEntity
40+
) {
41+
const errText = this.parseBadRequestError(error);
42+
this.toastr.error(errText);
43+
return EMPTY;
44+
}
45+
return throwError(() => error.message);
46+
}),
47+
);
48+
}
49+
private parseBadRequestError(response: HttpErrorResponse): string {
50+
const errorCode = `${response.status}${response.error['domain_code']}${String(response.error['error_code']).padStart(2, '0')}`;
51+
const errorName = translate(`errors-code.${errorCode}`);
52+
if (errorName === `errors-code.${errorCode}`) {
53+
return response.error.detail ?? translate('errors.unknown-error');
54+
}
55+
56+
return errorName;
57+
}
58+
}

projects/multidirectory-app/src/app/core/setup/setup-route.can-activate.guard.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import { MultidirectoryApiService } from '@services/multidirectory-api.service';
55
import { ToastrService } from 'ngx-toastr';
66
import { catchError, delay, map, Observable, of, switchMap } from 'rxjs';
77

8-
export const setupRouteGuardCanActivateFn = (
9-
route: ActivatedRouteSnapshot,
10-
): Observable<boolean | UrlTree> => {
8+
export const setupRouteGuardCanActivateFn = (route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> => {
119
const multidirectoryApi = inject(MultidirectoryApiService);
1210
const router = inject(Router);
1311
const toast = inject(ToastrService);
@@ -16,7 +14,6 @@ export const setupRouteGuardCanActivateFn = (
1614
return multidirectoryApi.checkSetup().pipe(
1715
catchError((err, caughtRx) => {
1816
if (err.status == 0 || calls > 5) {
19-
toast.error(translate('backend-status.backend-is-not-responding'));
2017
router.navigate(['/enable-backend']);
2118
return of(true);
2219
}

0 commit comments

Comments
 (0)