mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'develop' of ssh.dev.azure.com:v3/hugendubel/ISA/ISA-Frontend into develop
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { CustomerSearchNavigation } from '@shared/services/navigation';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { Injectable } from "@angular/core";
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { ApplicationProcess, ApplicationService } from "@core/application";
|
||||
import { DomainCheckoutService } from "@domain/checkout";
|
||||
import { logger } from "@isa/core/logging";
|
||||
import { CustomerSearchNavigation } from "@shared/services/navigation";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class CanActivateCustomerGuard {
|
||||
#logger = logger(() => ({
|
||||
context: "CanActivateCustomerGuard",
|
||||
tags: ["guard", "customer", "navigation"],
|
||||
}));
|
||||
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
@@ -14,36 +24,77 @@ export class CanActivateCustomerGuard {
|
||||
private readonly _navigation: CustomerSearchNavigation,
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
let lastActivatedProcessId = (
|
||||
async canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
{ url }: RouterStateSnapshot,
|
||||
) {
|
||||
if (url.startsWith("/kunde/customer/search/")) {
|
||||
const processId = Date.now(); // Generate a new process ID
|
||||
// Extract parts before and after the pattern
|
||||
const parts = url.split("/kunde/customer/");
|
||||
if (parts.length === 2) {
|
||||
const prefix = parts[0] + "/kunde/";
|
||||
const suffix = "customer/" + parts[1];
|
||||
|
||||
// Construct the new URL with process ID inserted
|
||||
const newUrl = `${prefix}${processId}/${suffix}`;
|
||||
|
||||
this.#logger.info("Redirecting to URL with process ID", () => ({
|
||||
originalUrl: url,
|
||||
newUrl,
|
||||
processId,
|
||||
}));
|
||||
|
||||
// Navigate to the new URL and prevent original navigation
|
||||
this._router.navigateByUrl(newUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const processes = await this._applicationService
|
||||
.getProcesses$("customer")
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart')
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "cart")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "cart-checkout")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedGoodsOutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'goods-out')
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "goods-out")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
const activatedProcessId = await this._applicationService
|
||||
.getActivatedProcessId$()
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Darf nur reinkommen wenn der aktuell aktive Tab ein Bestellabschluss Tab ist
|
||||
if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
|
||||
await this.fromCartCheckoutProcess(processes, lastActivatedCartCheckoutProcessId);
|
||||
if (
|
||||
!!lastActivatedCartCheckoutProcessId &&
|
||||
lastActivatedCartCheckoutProcessId === activatedProcessId
|
||||
) {
|
||||
await this.fromCartCheckoutProcess(
|
||||
processes,
|
||||
lastActivatedCartCheckoutProcessId,
|
||||
);
|
||||
return false;
|
||||
} else if (!!lastActivatedGoodsOutProcessId && lastActivatedGoodsOutProcessId === activatedProcessId) {
|
||||
} else if (
|
||||
!!lastActivatedGoodsOutProcessId &&
|
||||
lastActivatedGoodsOutProcessId === activatedProcessId
|
||||
) {
|
||||
await this.fromGoodsOutProcess(processes, lastActivatedGoodsOutProcessId);
|
||||
return false;
|
||||
}
|
||||
@@ -68,25 +119,28 @@ export class CanActivateCustomerGuard {
|
||||
const newProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: newProcessId,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`,
|
||||
});
|
||||
|
||||
await this.navigateToDefaultRoute(newProcessId);
|
||||
}
|
||||
|
||||
// Bei offener Bestellbestätigung und Klick auf Footer Kundensuche
|
||||
async fromCartCheckoutProcess(processes: ApplicationProcess[], processId: number) {
|
||||
async fromCartCheckoutProcess(
|
||||
processes: ApplicationProcess[],
|
||||
processId: number,
|
||||
) {
|
||||
// Um alle Checkout Daten zu resetten die mit dem Prozess assoziiert sind
|
||||
this._checkoutService.removeProcess({ processId });
|
||||
|
||||
// Ändere type cart-checkout zu cart
|
||||
this._applicationService.patchProcess(processId, {
|
||||
id: processId,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`,
|
||||
data: {},
|
||||
});
|
||||
|
||||
@@ -95,22 +149,31 @@ export class CanActivateCustomerGuard {
|
||||
}
|
||||
|
||||
// Bei offener Warenausgabe und Klick auf Footer Kundensuche
|
||||
async fromGoodsOutProcess(processes: ApplicationProcess[], processId: number) {
|
||||
const buyer = await this._checkoutService.getBuyer({ processId }).pipe(first()).toPromise();
|
||||
const customerFeatures = await this._checkoutService.getCustomerFeatures({ processId }).pipe(first()).toPromise();
|
||||
async fromGoodsOutProcess(
|
||||
processes: ApplicationProcess[],
|
||||
processId: number,
|
||||
) {
|
||||
const buyer = await this._checkoutService
|
||||
.getBuyer({ processId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const customerFeatures = await this._checkoutService
|
||||
.getCustomerFeatures({ processId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const name = buyer
|
||||
? customerFeatures?.b2b
|
||||
? buyer.organisation?.name
|
||||
? buyer.organisation?.name
|
||||
: buyer.lastName
|
||||
: buyer.lastName
|
||||
: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`;
|
||||
: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`;
|
||||
|
||||
// Ändere type goods-out zu cart
|
||||
this._applicationService.patchProcess(processId, {
|
||||
id: processId,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
name,
|
||||
});
|
||||
|
||||
@@ -119,12 +182,20 @@ export class CanActivateCustomerGuard {
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
|
||||
return !!processNumbers && processNumbers.length > 0 ? this.findMissingNumber(processNumbers) : 1;
|
||||
const processNumbers = processes?.map((process) =>
|
||||
Number(process?.name?.replace(/\D/g, "")),
|
||||
);
|
||||
return !!processNumbers && processNumbers.length > 0
|
||||
? this.findMissingNumber(processNumbers)
|
||||
: 1;
|
||||
}
|
||||
|
||||
findMissingNumber(processNumbers: number[]) {
|
||||
for (let missingNumber = 1; missingNumber < Math.max(...processNumbers); missingNumber++) {
|
||||
for (
|
||||
let missingNumber = 1;
|
||||
missingNumber < Math.max(...processNumbers);
|
||||
missingNumber++
|
||||
) {
|
||||
if (!processNumbers.find((number) => number === missingNumber)) {
|
||||
return missingNumber;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { coerceArray } from '@angular/cdk/coercion';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { coerceArray } from "@angular/cdk/coercion";
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { Config } from "@core/config";
|
||||
import { isNullOrUndefined } from "@utils/common";
|
||||
import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
|
||||
import { JwksValidationHandler } from "angular-oauth2-oidc-jwks";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
/**
|
||||
* Storage key for the URL to redirect to after login
|
||||
*/
|
||||
const REDIRECT_URL_KEY = "auth_redirect_url";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: "root",
|
||||
})
|
||||
export class AuthService {
|
||||
private readonly _initialized = new BehaviorSubject<boolean>(false);
|
||||
@@ -16,28 +21,39 @@ export class AuthService {
|
||||
}
|
||||
|
||||
private _authConfig: AuthConfig;
|
||||
|
||||
constructor(
|
||||
private _config: Config,
|
||||
private readonly _oAuthService: OAuthService,
|
||||
) {
|
||||
this._oAuthService.events?.subscribe((event) => {
|
||||
if (event.type === 'token_received') {
|
||||
console.log('SSO Token Expiration:', new Date(this._oAuthService.getAccessTokenExpiration()));
|
||||
if (event.type === "token_received") {
|
||||
console.log(
|
||||
"SSO Token Expiration:",
|
||||
new Date(this._oAuthService.getAccessTokenExpiration()),
|
||||
);
|
||||
|
||||
// Handle redirect after successful authentication
|
||||
setTimeout(() => {
|
||||
const redirectUrl = this._getAndClearRedirectUrl();
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (this._initialized.getValue()) {
|
||||
throw new Error('AuthService is already initialized');
|
||||
throw new Error("AuthService is already initialized");
|
||||
}
|
||||
|
||||
this._authConfig = this._config.get('@core/auth');
|
||||
this._authConfig = this._config.get("@core/auth");
|
||||
|
||||
this._authConfig.redirectUri = window.location.origin;
|
||||
|
||||
this._authConfig.silentRefreshRedirectUri = window.location.origin + '/silent-refresh.html';
|
||||
this._authConfig.silentRefreshRedirectUri =
|
||||
window.location.origin + "/silent-refresh.html";
|
||||
this._authConfig.useSilentRefresh = true;
|
||||
|
||||
this._oAuthService.configure(this._authConfig);
|
||||
@@ -55,12 +71,18 @@ export class AuthService {
|
||||
}
|
||||
|
||||
isIdTokenValid() {
|
||||
console.log('ID Token Expiration:', new Date(this._oAuthService.getIdTokenExpiration()));
|
||||
console.log(
|
||||
"ID Token Expiration:",
|
||||
new Date(this._oAuthService.getIdTokenExpiration()),
|
||||
);
|
||||
return this._oAuthService.hasValidIdToken();
|
||||
}
|
||||
|
||||
isAccessTokenValid() {
|
||||
console.log('ACCESS Token Expiration:', new Date(this._oAuthService.getAccessTokenExpiration()));
|
||||
console.log(
|
||||
"ACCESS Token Expiration:",
|
||||
new Date(this._oAuthService.getAccessTokenExpiration()),
|
||||
);
|
||||
return this._oAuthService.hasValidAccessToken();
|
||||
}
|
||||
|
||||
@@ -85,14 +107,31 @@ export class AuthService {
|
||||
if (isNullOrUndefined(token)) {
|
||||
return null;
|
||||
}
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
const base64Url = token.split(".")[1];
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
const encoded = window.atob(base64);
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the URL to redirect to after successful login
|
||||
*/
|
||||
_saveRedirectUrl(): void {
|
||||
localStorage.setItem(REDIRECT_URL_KEY, window.location.href);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and clears the saved redirect URL
|
||||
*/
|
||||
_getAndClearRedirectUrl(): string | null {
|
||||
const url = localStorage.getItem(REDIRECT_URL_KEY);
|
||||
localStorage.removeItem(REDIRECT_URL_KEY);
|
||||
return url;
|
||||
}
|
||||
|
||||
login() {
|
||||
this._saveRedirectUrl();
|
||||
this._oAuthService.initLoginFlow();
|
||||
}
|
||||
|
||||
@@ -109,7 +148,7 @@ export class AuthService {
|
||||
hasRole(role: string | string[]) {
|
||||
const roles = coerceArray(role);
|
||||
|
||||
const userRoles = this.getClaimByKey('role');
|
||||
const userRoles = this.getClaimByKey("role");
|
||||
|
||||
if (isNullOrUndefined(userRoles)) {
|
||||
return false;
|
||||
@@ -120,7 +159,10 @@ export class AuthService {
|
||||
|
||||
async refresh() {
|
||||
try {
|
||||
if (this._authConfig.responseType.includes('code') && this._authConfig.scope.includes('offline_access')) {
|
||||
if (
|
||||
this._authConfig.responseType.includes("code") &&
|
||||
this._authConfig.scope.includes("offline_access")
|
||||
) {
|
||||
await this._oAuthService.refreshToken();
|
||||
} else {
|
||||
await this._oAuthService.silentRefresh();
|
||||
|
||||
Reference in New Issue
Block a user