From 6c7ed31f2d8d494abfc9f17a8de9ac5b8de7cb23 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 12 Jul 2024 11:45:32 +0200 Subject: [PATCH 1/3] chore(notifications): 1188 prevent retry on notification requests --- .../core/api/http-error.interceptor.ts | 83 +++++++++++++------ 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/modules/core/api/http-error.interceptor.ts b/frontend/src/app/modules/core/api/http-error.interceptor.ts index f110860fad..b7b0f8ef41 100644 --- a/frontend/src/app/modules/core/api/http-error.interceptor.ts +++ b/frontend/src/app/modules/core/api/http-error.interceptor.ts @@ -26,8 +26,8 @@ import { ToastService } from 'src/app/modules/shared/components/toasts/toast.ser export class HttpErrorInterceptor implements HttpInterceptor { - // List of request.url that should not automatically display a toast but are handled custom (Can be extended later by METHOD) - private avoidList = [ '/api/notifications', '/api/notifications/*/approve' ]; + // List of request.url that should not automatically display a toast but are handled custom (Can be extended later by METHOD) and should not be retried + private avoidList = [ '/api/notifications', '/api/notifications/*/approve', '/api/notifications/*/cancel', '/api/notifications/*/close', '/api/notifications/*/update' ]; constructor(private readonly toastService: ToastService) { } @@ -36,36 +36,67 @@ export class HttpErrorInterceptor implements HttpInterceptor { request: HttpRequest>, next: HttpHandler, ): Observable>> { - return next.handle(request).pipe( - retry(1), - catchError((errorResponse: HttpErrorResponse) => { - // Possible ToDos: - // Add error code for specific errors "AUTH0" => Unauthorized, etc. - // Add logging server to store errors from the FE - // Intercept "console.error" and send to logging server for further analysis - const { error, message } = errorResponse; - const errorMessage = !error.message ? message : `Backend returned code ${ error.status }: ${ error.message }`; - - // Check if the request URL matches any pattern in the avoidList - if (!this.isOnAlreadyHandledUrlList(request.url)) { - this.toastService.error(errorMessage); - } - - return throwError(() => errorResponse); - }), - ); + const requestUrl = this.stripBaseUrl(request.url); + const isHandled = this.isOnAlreadyHandledUrlList(requestUrl); + + if (isHandled) { + // Handle the request without retry if it matches the avoidList + return next.handle(request).pipe( + catchError((errorResponse: HttpErrorResponse) => this.handleError(request, errorResponse)), + ); + } else { + // Retry the request once if it does not match the avoidList + return next.handle(request).pipe( + retry(1), + catchError((errorResponse: HttpErrorResponse) => this.handleError(request, errorResponse)), + ); + } + } + + private handleError(request: HttpRequest, errorResponse: HttpErrorResponse): Observable { + const { error, message } = errorResponse; + const errorMessage = !error.message ? message : `Backend returned code ${ error.status }: ${ error.message }`; + + // Check if the request URL matches any pattern in the avoidList + if (!this.isOnAlreadyHandledUrlList(this.stripBaseUrl(request.url))) { + this.toastService.error(errorMessage); + } + + return throwError(() => errorResponse); } -// Helper method to check if the URL matches any pattern in the avoidList + // Helper method to check if the URL matches any pattern in the avoidList private isOnAlreadyHandledUrlList(url: string): boolean { - return !this.avoidList.some(pattern => this.urlMatchesPattern(url, pattern)); + return this.avoidList.some(pattern => this.urlMatchesPattern(url, pattern)); } -// Helper method to check if the URL matches a wildcard pattern + // Helper method to check if the URL matches a wildcard pattern private urlMatchesPattern(url: string, pattern: string): boolean { - const regexPattern = pattern.replace(/\*/g, '.*'); - const regex = new RegExp(`^${regexPattern}$`); - return regex.test(url); + // Convert wildcard pattern to regex + const escapedPattern = pattern.split('*').map(escapeRegExp).join('.*'); + const regexPattern = `^${ escapedPattern }$`; + const regex = new RegExp(regexPattern); + const matches = regex.test(url); + return matches; + } + + // Helper method to strip base URL from the request URL + private stripBaseUrl(url: string): string { + const baseUrlPattern = /^(https?:\/\/[^\/]+)(\/.*)?$/; + const match = baseUrlPattern.exec(url); + return match && match[2] ? match[2] : url; } +} +// Helper function to escape regex special characters in a string +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } + + + + + + + + From e251b82934ccfbc3a595b21487fbb4fd58e184e8 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 12 Jul 2024 11:53:00 +0200 Subject: [PATCH 2/3] chore(notifications): 1188 prevent retry on notification requests --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 639c92f7ed..c3657c3817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha - #1173 Update IRS-Helm from 7.1.4 to 7.2.0 - updated Compatibility Matrix - #1082 fix duplicate key errors when synchronizing assets with IRS - #970 fixed bug where the right operand of policies was not showing up in table and detailed view +- #1188 prevent retry requests for notification actions to prevent duplicate error messages in history ## [12.0.0 - 05.07.2024] From 65e92eb7efe50babbdc897dea506566ec99017e5 Mon Sep 17 00:00:00 2001 From: Martin Maul Date: Fri, 12 Jul 2024 12:01:12 +0200 Subject: [PATCH 3/3] chore(notifications): 1188 prevent retry on notification requests --- .../src/app/modules/core/api/http-error.interceptor.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/modules/core/api/http-error.interceptor.ts b/frontend/src/app/modules/core/api/http-error.interceptor.ts index b7b0f8ef41..c4c676c07f 100644 --- a/frontend/src/app/modules/core/api/http-error.interceptor.ts +++ b/frontend/src/app/modules/core/api/http-error.interceptor.ts @@ -76,15 +76,13 @@ export class HttpErrorInterceptor implements HttpInterceptor { const escapedPattern = pattern.split('*').map(escapeRegExp).join('.*'); const regexPattern = `^${ escapedPattern }$`; const regex = new RegExp(regexPattern); - const matches = regex.test(url); - return matches; + return regex.test(url); } // Helper method to strip base URL from the request URL private stripBaseUrl(url: string): string { - const baseUrlPattern = /^(https?:\/\/[^\/]+)(\/.*)?$/; - const match = baseUrlPattern.exec(url); - return match && match[2] ? match[2] : url; + const baseUrlPattern = /^(https?:\/\/[^/]+)(\/.*)?$/; + return baseUrlPattern.exec(url)?.[2] ?? url; } }