new initialization process, keycloak update 24.0.4
This commit is contained in:
parent
747435bfba
commit
dc9adb151d
|
|
@ -37,7 +37,7 @@
|
|||
"dayjs": "^1.11.11",
|
||||
"express": "^4.18.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"keycloak-js": "^23.0.7",
|
||||
"keycloak-js": "^24.0.4",
|
||||
"memoize-one": "^6.0.0",
|
||||
"on-change": "^5.0.1",
|
||||
"primeflex": "^3.3.1",
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { provideAnimations } from '@angular/platform-browser/animations';
|
|||
import { environment } from '../environments/environment';
|
||||
import { routes } from './app.routes';
|
||||
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
||||
import { KeycloakInitializerService } from './services/keycloak-initializer.service';
|
||||
import { KeycloakService } from './services/keycloak.service';
|
||||
import { SelectOptionsService } from './services/select-options.service';
|
||||
import { UserService } from './services/user.service';
|
||||
// provideClientHydration()
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
|
|
@ -16,9 +16,11 @@ export const appConfig: ApplicationConfig = {
|
|||
{ provide: KeycloakService },
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: initializeKeycloak,
|
||||
// useFactory: initializeKeycloak,
|
||||
useFactory: (keycloakInitializer: KeycloakInitializerService) => async () => await keycloakInitializer.initialize(),
|
||||
multi: true,
|
||||
deps: [KeycloakService],
|
||||
// deps: [KeycloakService],
|
||||
deps: [KeycloakInitializerService],
|
||||
},
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
|
|
@ -40,24 +42,17 @@ export const appConfig: ApplicationConfig = {
|
|||
}),
|
||||
),
|
||||
provideAnimations(),
|
||||
|
||||
// {provide: LOCALE_ID, useValue: 'en-US' }
|
||||
],
|
||||
};
|
||||
function initUserService(userService: UserService) {
|
||||
return () => {
|
||||
//selectOptions.init();
|
||||
};
|
||||
}
|
||||
function initServices(selectOptions: SelectOptionsService) {
|
||||
return () => {
|
||||
selectOptions.init();
|
||||
return async () => {
|
||||
await selectOptions.init();
|
||||
};
|
||||
}
|
||||
|
||||
function initializeKeycloak(keycloak: KeycloakService) {
|
||||
return () =>
|
||||
keycloak.init({
|
||||
return async () => {
|
||||
const authenticated = await keycloak.init({
|
||||
config: {
|
||||
url: environment.keycloak.url,
|
||||
realm: environment.keycloak.realm,
|
||||
|
|
@ -68,4 +63,6 @@ function initializeKeycloak(keycloak: KeycloakService) {
|
|||
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
||||
},
|
||||
});
|
||||
console.log(`--->${authenticated}`);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
</div>
|
||||
<div class="col-12 md:col-3 text-500">
|
||||
<div class="text-black font-bold line-height-3 mb-3">Actions</div>
|
||||
<a *ngIf="!userService.isLoggedIn()" (click)="login()" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline">Login</a>
|
||||
<a *ngIf="userService.isLoggedIn()" [routerLink]="['/account']" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline">Account</a>
|
||||
<a *ngIf="userService.isLoggedIn()" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline" (click)="userService.logout()">Log Out</a>
|
||||
<a *ngIf="!keycloakService.isLoggedIn()" (click)="login()" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline">Login</a>
|
||||
<a *ngIf="keycloakService.isLoggedIn()" [routerLink]="['/account']" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline">Account</a>
|
||||
<a *ngIf="keycloakService.isLoggedIn()" class="text-500 line-height-3 block cursor-pointer mb-2 no-underline" (click)="keycloakService.logout()">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { SidebarModule } from 'primeng/sidebar';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
import { SharedModule } from '../../shared/shared/shared.module';
|
||||
@Component({
|
||||
selector: 'footer',
|
||||
|
|
@ -12,8 +12,10 @@ import { SharedModule } from '../../shared/shared/shared.module';
|
|||
export class FooterComponent {
|
||||
privacyVisible = false;
|
||||
termsVisible = false;
|
||||
constructor(public userService: UserService) {}
|
||||
constructor(public keycloakService: KeycloakService) {}
|
||||
login() {
|
||||
this.userService.login(window.location.href);
|
||||
this.keycloakService.login({
|
||||
redirectUri: window.location.href,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
<p-tabMenu [model]="tabItems" ariaLabelledBy="label" styleClass="flex" [activeItem]="activeItem"> </p-tabMenu>
|
||||
<p-menubar [model]="menuItems"></p-menubar>
|
||||
<p-menubar [model]="loginItems"></p-menubar>
|
||||
<div *ngIf="user$ | async as user; else empty">Welcome, {{ user.firstName }}</div>
|
||||
@if(user){
|
||||
<div>Welcome, {{ user.firstName }}</div>
|
||||
}
|
||||
<ng-template #empty> </ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import { TabMenuModule } from 'primeng/tabmenu';
|
|||
import { Observable } from 'rxjs';
|
||||
import { KeycloakUser } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
import { map2User } from '../../utils/utils';
|
||||
@Component({
|
||||
selector: 'header',
|
||||
standalone: true,
|
||||
|
|
@ -27,12 +28,14 @@ export class HeaderComponent {
|
|||
public menuItems: MenuItem[];
|
||||
activeItem;
|
||||
faUserGear = faUserGear;
|
||||
constructor(public userService: UserService, private router: Router) {}
|
||||
constructor(public keycloakService: KeycloakService, private router: Router) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.user$ = this.userService.getUserObservable();
|
||||
this.user$.subscribe(u => {
|
||||
this.user = u;
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
this.user = map2User(token);
|
||||
//this.user$ = this.keycloakService
|
||||
// this.user$.subscribe(u => {
|
||||
// this.user = u;
|
||||
this.menuItems = [
|
||||
{
|
||||
label: 'User Actions',
|
||||
|
|
@ -42,48 +45,48 @@ export class HeaderComponent {
|
|||
label: 'Account',
|
||||
icon: 'pi pi-user',
|
||||
routerLink: `/account`,
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'Create Listing',
|
||||
icon: 'pi pi-plus-circle',
|
||||
routerLink: '/createBusinessListing',
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'My Listings',
|
||||
icon: 'pi pi-list',
|
||||
routerLink: '/myListings',
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'My Favorites',
|
||||
icon: 'pi pi-star',
|
||||
routerLink: '/myFavorites',
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'EMail Us',
|
||||
icon: 'fa-regular fa-envelope',
|
||||
routerLink: '/emailUs',
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'Logout',
|
||||
icon: 'fa-solid fa-right-from-bracket',
|
||||
routerLink: '/logout',
|
||||
visible: this.isUserLogedIn(),
|
||||
visible: this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'Login',
|
||||
icon: 'fa-solid fa-right-from-bracket',
|
||||
command: () => this.login(),
|
||||
visible: !this.isUserLogedIn(),
|
||||
visible: !this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
});
|
||||
// });
|
||||
this.tabItems = [
|
||||
{
|
||||
label: 'Businesses for Sale',
|
||||
|
|
@ -102,12 +105,12 @@ export class HeaderComponent {
|
|||
{
|
||||
label: 'Login',
|
||||
command: () => this.login(),
|
||||
visible: !this.isUserLogedIn(),
|
||||
visible: !this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
{
|
||||
label: 'Register',
|
||||
command: () => this.register(),
|
||||
visible: !this.isUserLogedIn(),
|
||||
visible: !this.keycloakService.isLoggedIn(),
|
||||
},
|
||||
];
|
||||
this.activeItem = this.tabItems[0];
|
||||
|
|
@ -116,13 +119,12 @@ export class HeaderComponent {
|
|||
navigateWithState(dest: string, state: any) {
|
||||
this.router.navigate([dest], { state: state });
|
||||
}
|
||||
isUserLogedIn() {
|
||||
return this.userService?.isLoggedIn();
|
||||
}
|
||||
login() {
|
||||
this.userService.login(window.location.href);
|
||||
this.keycloakService.login({
|
||||
redirectUri: window.location.href,
|
||||
});
|
||||
}
|
||||
register() {
|
||||
this.userService.register(`${window.location.origin}/account`);
|
||||
this.keycloakService.register({ redirectUri: `${window.location.origin}/account` });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
|
||||
@Component({
|
||||
selector: 'logout',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterModule],
|
||||
template:``
|
||||
template: ``,
|
||||
})
|
||||
export class LogoutComponent {
|
||||
constructor(private userService:UserService){
|
||||
userService.logout();
|
||||
constructor(public keycloakService: KeycloakService) {
|
||||
sessionStorage.removeItem('USERID');
|
||||
keycloakService.logout(window.location.origin + '/home');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,30 @@
|
|||
import { CanMatchFn, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { CanMatchFn, Router, UrlTree } from '@angular/router';
|
||||
|
||||
// Services
|
||||
import { UserService } from '../services/user.service';
|
||||
|
||||
import { KeycloakInitializerService } from '../services/keycloak-initializer.service';
|
||||
import { KeycloakService } from '../services/keycloak.service';
|
||||
import { createLogger } from '../utils/utils';
|
||||
const logger = createLogger('authGuard');
|
||||
export const authGuard: CanMatchFn = async (route, segments): Promise<boolean | UrlTree> => {
|
||||
const router = inject(Router);
|
||||
const userService = inject(UserService);
|
||||
|
||||
const authenticated: boolean = userService.isLoggedIn();
|
||||
const keycloakService = inject(KeycloakService);
|
||||
const keycloakInitializer = inject(KeycloakInitializerService);
|
||||
if (!keycloakInitializer.isInitialized()) {
|
||||
await keycloakInitializer.initialize();
|
||||
}
|
||||
logger.info('###-> calling isLoggedIn()');
|
||||
const authenticated = keycloakService.isLoggedIn();
|
||||
if (!authenticated) {
|
||||
console.log(window.location.origin)
|
||||
console.log(window.location.href)
|
||||
await userService.login(`${window.location.origin}${segments['url']}`);
|
||||
console.log(window.location.origin);
|
||||
console.log(window.location.href);
|
||||
keycloakService.login({
|
||||
redirectUri: `${window.location.origin}${segments['url']}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Get the user Keycloak roles and the required from the route
|
||||
const roles: string[] = userService.getUserRoles();//keycloakService.getUserRoles(true);
|
||||
const roles: string[] = keycloakService.getUserRoles(true);
|
||||
const requiredRoles = route.data?.['roles'];
|
||||
|
||||
// Allow the user to proceed if no additional roles are required to access the route
|
||||
|
|
@ -24,15 +32,11 @@ export const authGuard: CanMatchFn = async (route, segments): Promise<boolean |
|
|||
return true;
|
||||
}
|
||||
|
||||
// Allow the user to proceed if ALL of the required roles are present
|
||||
const authorized = requiredRoles.every((role) => roles.includes(role));
|
||||
// Allow the user to proceed if ONE of the required roles is present
|
||||
//const authorized = requiredRoles.some((role) => roles.includes(role));
|
||||
const authorized = requiredRoles.every(role => roles.includes(role));
|
||||
|
||||
if (authorized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Display my custom HTTP 403 access denied page
|
||||
return router.createUrlTree(['/access']);
|
||||
return router.createUrlTree(['/home']);
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpInterceptorFn, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { v4 } from 'uuid';
|
||||
import { LoadingService } from '../services/loading.service';
|
||||
|
|
@ -8,17 +8,15 @@ import { LoadingService } from '../services/loading.service';
|
|||
export class LoadingInterceptor implements HttpInterceptor {
|
||||
constructor(private loadingService: LoadingService) {}
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
console.log("Intercepting Requests")
|
||||
const requestId = `HTTP-${v4()}`;
|
||||
this.loadingService.startLoading(requestId, request.url);
|
||||
|
||||
// return next.handle(request);
|
||||
return next.handle(request).pipe(
|
||||
tap({
|
||||
finalize: () => this.loadingService.stopLoading(requestId), // Stoppt den Ladevorgang, wenn die Anfrage abgeschlossen ist
|
||||
// Beachte, dass 'error' und 'complete' hier entfernt wurden, da 'finalize' in allen Fällen aufgerufen wird,
|
||||
// egal ob die Anfrage erfolgreich war, einen Fehler geworfen hat oder abgeschlossen wurde.
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,15 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Mauricio Gemelli Vigolo and contributors.
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style license that can be
|
||||
* found in the LICENSE file at https://github.com/mauriciovigolo/keycloak-angular/blob/main/LICENSE.md
|
||||
*/
|
||||
|
||||
/**
|
||||
* Keycloak event types, as described at the keycloak-js documentation:
|
||||
* https://www.keycloak.org/docs/latest/securing_apps/index.html#callback-events
|
||||
*/
|
||||
export enum KeycloakEventType {
|
||||
/**
|
||||
* Called if there was an error during authentication.
|
||||
|
|
@ -33,7 +45,7 @@ export enum KeycloakEventType {
|
|||
/**
|
||||
* Called when a AIA has been requested by the application.
|
||||
*/
|
||||
OnActionUpdate
|
||||
OnActionUpdate,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,14 +11,7 @@ import { HttpRequest } from '@angular/common/http';
|
|||
/**
|
||||
* HTTP Methods
|
||||
*/
|
||||
export type HttpMethods =
|
||||
| 'GET'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'OPTIONS'
|
||||
| 'HEAD'
|
||||
| 'PATCH';
|
||||
export type HttpMethods = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
|
||||
|
||||
/**
|
||||
* ExcludedUrl type may be used to specify the url and the HTTP method that
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { BusinessListing, User } from '../../../../../../bizmatch-server/src/mod
|
|||
import { KeycloakUser, ListingCriteria, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { HistoryService } from '../../../services/history.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { MailService } from '../../../services/mail.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
|
|
@ -64,6 +65,7 @@ export class DetailsBusinessListingComponent {
|
|||
private messageService: MessageService,
|
||||
private sanitizer: DomSanitizer,
|
||||
public historyService: HistoryService,
|
||||
public keycloakService: KeycloakService,
|
||||
) {
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
|
|
@ -71,9 +73,7 @@ export class DetailsBusinessListingComponent {
|
|||
}
|
||||
});
|
||||
this.mailinfo = { sender: {}, userId: '', email: '', url: environment.mailinfoUrl };
|
||||
this.userService.getUserObservable().subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
this.user;
|
||||
this.criteria = onChange(getCriteriaStateObject(), getSessionStorageHandler);
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ export class DetailsBusinessListingComponent {
|
|||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.userService.hasAdminRole();
|
||||
return this.keycloakService.getUserRoles(true).includes('ADMIN');
|
||||
}
|
||||
async mail() {
|
||||
this.mailinfo.email = this.listingUser.email;
|
||||
|
|
|
|||
|
|
@ -9,12 +9,13 @@ import { CommercialPropertyListing, User } from '../../../../../../bizmatch-serv
|
|||
import { ErrorResponse, KeycloakUser, ListingCriteria, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { HistoryService } from '../../../services/history.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { MailService } from '../../../services/mail.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { getCriteriaStateObject, getSessionStorageHandler } from '../../../utils/utils';
|
||||
import { getCriteriaStateObject, getSessionStorageHandler, map2User } from '../../../utils/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-details-commercial-property-listing',
|
||||
|
|
@ -65,22 +66,23 @@ export class DetailsCommercialPropertyListingComponent {
|
|||
private messageService: MessageService,
|
||||
private sanitizer: DomSanitizer,
|
||||
public historyService: HistoryService,
|
||||
public keycloakService: KeycloakService,
|
||||
) {
|
||||
this.mailinfo = { sender: {}, userId: '', email: '', url: environment.mailinfoUrl };
|
||||
this.userService.getUserObservable().subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
this.criteria = onChange(getCriteriaStateObject(), getSessionStorageHandler);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
this.user = map2User(token);
|
||||
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty'));
|
||||
this.propertyImages = await this.listingsService.getPropertyImages(this.listing.id);
|
||||
this.listingUser = await this.userService.getById(this.listing.userId);
|
||||
this.description = this.sanitizer.bypassSecurityTrustHtml(this.listing.description);
|
||||
}
|
||||
isAdmin() {
|
||||
return this.userService.hasAdminRole();
|
||||
return this.keycloakService.getUserRoles(true).includes('ADMIN');
|
||||
}
|
||||
async mail() {
|
||||
this.mailinfo.email = this.listingUser.email;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@if( user?.email===(user$| async)?.email || isAdmin()){
|
||||
@if( user?.email===keycloakUser?.email || isAdmin()){
|
||||
<button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/account', user.id]"></button>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,10 +9,12 @@ import { KeycloakUser, ListingCriteria } from '../../../../../../bizmatch-server
|
|||
import { environment } from '../../../../environments/environment';
|
||||
import { HistoryService } from '../../../services/history.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { map2User } from '../../../utils/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-details-user',
|
||||
|
|
@ -26,6 +28,7 @@ export class DetailsUserComponent {
|
|||
private id: string | undefined = this.activatedRoute.snapshot.params['id'] as string | undefined;
|
||||
user: User;
|
||||
user$: Observable<KeycloakUser>;
|
||||
keycloakUser: KeycloakUser;
|
||||
environment = environment;
|
||||
criteria: ListingCriteria;
|
||||
businessListings: BusinessListing[];
|
||||
|
|
@ -44,6 +47,7 @@ export class DetailsUserComponent {
|
|||
private sanitizer: DomSanitizer,
|
||||
private imageService: ImageService,
|
||||
public historyService: HistoryService,
|
||||
public keycloakService: KeycloakService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
|
|
@ -53,12 +57,14 @@ export class DetailsUserComponent {
|
|||
// Zuweisen der Ergebnisse zu den Member-Variablen der Klasse
|
||||
this.businessListings = results[0];
|
||||
this.commercialPropListings = results[1];
|
||||
this.user$ = this.userService.getUserObservable();
|
||||
//this.user$ = this.userService.getUserObservable();
|
||||
const token = await this.keycloakService.getToken();
|
||||
this.keycloakUser = map2User(token);
|
||||
this.companyOverview = this.sanitizer.bypassSecurityTrustHtml(this.user.companyOverview);
|
||||
this.offeredServices = this.sanitizer.bypassSecurityTrustHtml(this.user.offeredServices);
|
||||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.userService.hasAdminRole();
|
||||
return this.keycloakService.getUserRoles(true).includes('ADMIN');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<div class="align-items-center flex-grow-1 justify-content-between hidden lg:flex absolute lg:static w-full left-0 top-100 px-6 lg:px-0 shadow-2 lg:shadow-none z-2">
|
||||
<section></section>
|
||||
<div class="flex justify-content-between lg:block border-top-1 lg:border-top-none border-gray-800 py-3 lg:py-0 mt-3 lg:mt-0">
|
||||
@if(userService.isLoggedIn()){
|
||||
@if(keycloakService.isLoggedIn()){
|
||||
<p-button label="Account" class="ml-3 font-bold" [outlined]="true" severity="secondary" [routerLink]="['/account']"></p-button>
|
||||
} @else {
|
||||
<p-button label="Log In" class="ml-3 font-bold" [outlined]="true" severity="secondary" (click)="login()"></p-button>
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
pRipple
|
||||
label="Create Your Listing"
|
||||
class="block mt-7 mb-7 lg:mb-0 p-button-rounded p-button-success p-button-lg font-medium"
|
||||
[routerLink]="userService.isLoggedIn() ? '/createBusinessListing' : '/pricing'"
|
||||
[routerLink]="keycloakService.isLoggedIn() ? '/createBusinessListing' : '/pricing'"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,10 @@ import { CheckboxModule } from 'primeng/checkbox';
|
|||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { StyleClassModule } from 'primeng/styleclass';
|
||||
import { Observable } from 'rxjs';
|
||||
import { KeycloakUser, ListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { ListingCriteria } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
import { ListingsService } from '../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../services/select-options.service';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { getCriteriaStateObject, getSessionStorageHandler, resetCriteria } from '../../utils/utils';
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
|
|
@ -27,14 +26,12 @@ export class HomeComponent {
|
|||
maxPrice: string;
|
||||
minPrice: string;
|
||||
criteria: ListingCriteria;
|
||||
user$: Observable<KeycloakUser>;
|
||||
states = [];
|
||||
public constructor(private router: Router, private activatedRoute: ActivatedRoute, public selectOptions: SelectOptionsService, public userService: UserService, private listingsService: ListingsService) {
|
||||
public constructor(private router: Router, private activatedRoute: ActivatedRoute, public selectOptions: SelectOptionsService, public keycloakService: KeycloakService, private listingsService: ListingsService) {
|
||||
this.criteria = onChange(getCriteriaStateObject(), getSessionStorageHandler);
|
||||
resetCriteria(this.criteria);
|
||||
}
|
||||
async ngOnInit() {
|
||||
this.user$ = this.userService.getUserObservable();
|
||||
if (this.activeTabAction === 'business' || this.activeTabAction === 'commercialProperty') {
|
||||
const statesResult = await this.listingsService.getAllStates(this.activeTabAction);
|
||||
this.states = statesResult.map(s => s.state).map(ls => ({ name: this.selectOptions.getState(ls as string), value: ls }));
|
||||
|
|
@ -57,9 +54,11 @@ export class HomeComponent {
|
|||
}
|
||||
|
||||
login() {
|
||||
this.userService.login(window.location.href);
|
||||
this.keycloakService.login({
|
||||
redirectUri: window.location.href,
|
||||
});
|
||||
}
|
||||
register() {
|
||||
this.userService.register(`${window.location.origin}/account`);
|
||||
this.keycloakService.register({ redirectUri: `${window.location.origin}/account` });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,12 +47,7 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
(click)="userService.logout()"
|
||||
routerLinkActive="text-blue-500"
|
||||
pRipple
|
||||
class="flex align-items-center cursor-pointer p-3 border-round text-800 hover:surface-200 transition-duration-150 transition-colors no-underline"
|
||||
>
|
||||
<a (click)="logout()" routerLinkActive="text-blue-500" pRipple class="flex align-items-center cursor-pointer p-3 border-round text-800 hover:surface-200 transition-duration-150 transition-colors no-underline">
|
||||
<fa-icon [icon]="faRightFromBracket" class="mr-2 flex"></fa-icon>
|
||||
<span class="font-medium hidden md:block">Logout</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,27 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { CheckboxModule } from 'primeng/checkbox';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { StyleClassModule } from 'primeng/styleclass';
|
||||
import { SelectOptionsService } from '../../services/select-options.service';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ToggleButtonModule } from 'primeng/togglebutton';
|
||||
import { TagModule } from 'primeng/tag';
|
||||
import data from '../../../assets/data/listings.json';
|
||||
import { ActivatedRoute, NavigationEnd, Router, RouterModule } from '@angular/router';
|
||||
import { InputTextareaModule } from 'primeng/inputtextarea';
|
||||
import { ChipModule } from 'primeng/chip';
|
||||
import { DividerModule } from 'primeng/divider';
|
||||
import { RippleModule } from 'primeng/ripple';
|
||||
import { Component } from '@angular/core';
|
||||
import { NavigationEnd, Router, RouterModule } from '@angular/router';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import { faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faRightFromBracket } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DividerModule } from 'primeng/divider';
|
||||
import { RippleModule } from 'primeng/ripple';
|
||||
import { StyleClassModule } from 'primeng/styleclass';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
|
||||
@Component({
|
||||
selector: 'menu-account',
|
||||
standalone: true,
|
||||
imports: [CommonModule, StyleClassModule, ButtonModule, DividerModule, RouterModule, RippleModule, FontAwesomeModule],
|
||||
templateUrl: './menu-account.component.html',
|
||||
styleUrl: './menu-account.component.scss'
|
||||
styleUrl: './menu-account.component.scss',
|
||||
})
|
||||
export class MenuAccountComponent {
|
||||
activeLink: string;
|
||||
faEnvelope = faEnvelope;
|
||||
faRightFromBracket = faRightFromBracket;
|
||||
constructor(private router: Router,public userService:UserService) {
|
||||
constructor(private router: Router, public keycloakService: KeycloakService) {
|
||||
// Abonniere Router-Events, um den aktiven Link zu ermitteln
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
|
|
@ -39,4 +29,8 @@ export class MenuAccountComponent {
|
|||
}
|
||||
});
|
||||
}
|
||||
logout() {
|
||||
sessionStorage.removeItem('USERID');
|
||||
this.keycloakService.logout(window.location.origin + '/home');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { KeycloakService } from '../../services/keycloak.service';
|
||||
import { SharedModule } from '../../shared/shared/shared.module';
|
||||
import { UserService } from '../../services/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pricing',
|
||||
standalone: true,
|
||||
imports: [SharedModule],
|
||||
templateUrl: './pricing.component.html',
|
||||
styleUrl: './pricing.component.scss'
|
||||
styleUrl: './pricing.component.scss',
|
||||
})
|
||||
export class PricingComponent {
|
||||
constructor(private userService:UserService){}
|
||||
constructor(public keycloakService: KeycloakService) {}
|
||||
register() {
|
||||
this.userService.register(`${window.location.origin}/account`);
|
||||
this.keycloakService.register({ redirectUri: `${window.location.origin}/account` });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,13 @@ import { environment } from '../../../../environments/environment';
|
|||
import { ImageCropperComponent, stateOptions } from '../../../components/image-cropper/image-cropper.component';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { SubscriptionsService } from '../../../services/subscriptions.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { map2User } from '../../../utils/utils';
|
||||
import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
||||
@Component({
|
||||
selector: 'app-account',
|
||||
|
|
@ -60,12 +62,14 @@ export class AccountComponent {
|
|||
public dialogService: DialogService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private imageService: ImageService,
|
||||
private keycloakService: KeycloakService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
if (this.id) {
|
||||
this.user = await this.userService.getById(this.id);
|
||||
} else {
|
||||
const keycloakUser = this.userService.getKeycloakUser();
|
||||
const token = await this.keycloakService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
try {
|
||||
this.user = await this.userService.getByMail(email);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
|||
import { lastValueFrom } from 'rxjs';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { createDefaultBusinessListing, routeListingWithState } from '../../../utils/utils';
|
||||
import { createDefaultBusinessListing, map2User, routeListingWithState } from '../../../utils/utils';
|
||||
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
||||
|
|
@ -23,6 +23,7 @@ import { InputNumberModule } from '../../../components/inputnumber/inputnumber.c
|
|||
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
|
|
@ -99,6 +100,7 @@ export class EditBusinessListingComponent {
|
|||
public dialogService: DialogService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private route: ActivatedRoute,
|
||||
private keycloakService: KeycloakService,
|
||||
) {
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
|
|
@ -115,11 +117,13 @@ export class EditBusinessListingComponent {
|
|||
});
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
if (this.mode === 'edit') {
|
||||
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'business'));
|
||||
} else {
|
||||
this.listing = createDefaultBusinessListing();
|
||||
this.listing.userId = await this.userService.getId();
|
||||
this.listing.userId = await this.userService.getId(keycloakUser.email);
|
||||
if (this.data) {
|
||||
this.listing.title = this.data?.title;
|
||||
this.listing.description = this.data?.description;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
|||
import { lastValueFrom } from 'rxjs';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { createDefaultCommercialPropertyListing, routeListingWithState } from '../../../utils/utils';
|
||||
import { createDefaultCommercialPropertyListing, map2User, routeListingWithState } from '../../../utils/utils';
|
||||
|
||||
import { DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { HttpEventType } from '@angular/common/http';
|
||||
|
|
@ -26,6 +26,7 @@ import { InputNumberModule } from '../../../components/inputnumber/inputnumber.c
|
|||
import { ArrayToStringPipe } from '../../../pipes/array-to-string.pipe';
|
||||
import { GeoService } from '../../../services/geo.service';
|
||||
import { ImageService } from '../../../services/image.service';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { LoadingService } from '../../../services/loading.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
|
|
@ -106,6 +107,7 @@ export class EditCommercialPropertyListingComponent {
|
|||
public dialogService: DialogService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private route: ActivatedRoute,
|
||||
private keycloakService: KeycloakService,
|
||||
) {
|
||||
// Abonniere Router-Events, um den aktiven Link zu ermitteln
|
||||
this.router.events.subscribe(event => {
|
||||
|
|
@ -123,11 +125,13 @@ export class EditCommercialPropertyListingComponent {
|
|||
});
|
||||
}
|
||||
async ngOnInit() {
|
||||
const token = await this.keycloakService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
if (this.mode === 'edit') {
|
||||
this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'commercialProperty'));
|
||||
} else {
|
||||
this.listing = createDefaultCommercialPropertyListing();
|
||||
this.listing.userId = await this.userService.getId();
|
||||
this.listing.userId = await this.userService.getId(keycloakUser.email);
|
||||
this.listing.imagePath = uuidv4();
|
||||
if (this.data) {
|
||||
this.listing.title = this.data?.title;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { KeycloakUser, ListingType } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { map2User } from '../../../utils/utils';
|
||||
import { MenuAccountComponent } from '../../menu-account/menu-account.component';
|
||||
|
||||
@Component({
|
||||
|
|
@ -17,11 +18,10 @@ export class FavoritesComponent {
|
|||
user: KeycloakUser;
|
||||
listings: Array<ListingType> = []; //= dataListings as unknown as Array<BusinessListing>;
|
||||
favorites: Array<ListingType>;
|
||||
constructor(public userService: UserService, private listingsService: ListingsService, public selectOptions: SelectOptionsService) {
|
||||
this.user = this.userService.getKeycloakUser();
|
||||
}
|
||||
constructor(public keycloakService: KeycloakService, private listingsService: ListingsService, public selectOptions: SelectOptionsService) {}
|
||||
async ngOnInit() {
|
||||
// this.listings=await lastValueFrom(this.listingsService.getAllListings());
|
||||
const token = await this.keycloakService.getToken();
|
||||
this.user = map2User(token);
|
||||
this.favorites = this.listings.filter(l => l.favoritesForUser?.includes(this.user.id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import { ChangeDetectorRef, Component } from '@angular/core';
|
|||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { ListingType } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
import { KeycloakService } from '../../../services/keycloak.service';
|
||||
import { ListingsService } from '../../../services/listings.service';
|
||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { SharedModule } from '../../../shared/shared/shared.module';
|
||||
import { map2User } from '../../../utils/utils';
|
||||
import { MenuAccountComponent } from '../../menu-account/menu-account.component';
|
||||
@Component({
|
||||
selector: 'app-my-listing',
|
||||
|
|
@ -21,6 +23,7 @@ export class MyListingComponent {
|
|||
user: User;
|
||||
constructor(
|
||||
public userService: UserService,
|
||||
public keycloakService: KeycloakService,
|
||||
private listingsService: ListingsService,
|
||||
private cdRef: ChangeDetectorRef,
|
||||
public selectOptions: SelectOptionsService,
|
||||
|
|
@ -28,7 +31,9 @@ export class MyListingComponent {
|
|||
private messageService: MessageService,
|
||||
) {}
|
||||
async ngOnInit() {
|
||||
const keycloakUser = this.userService.getKeycloakUser();
|
||||
// const keycloakUser = this.userService.getKeycloakUser();
|
||||
const token = await this.keycloakService.getToken();
|
||||
const keycloakUser = map2User(token);
|
||||
const email = keycloakUser.email;
|
||||
this.user = await this.userService.getByMail(email);
|
||||
const result = await Promise.all([await this.listingsService.getListingByUserId(this.user.id, 'business'), await this.listingsService.getListingByUserId(this.user.id, 'commercialProperty')]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import { inject } from '@angular/core';
|
||||
import { ResolveFn } from '@angular/router';
|
||||
import { KeycloakService } from '../services/keycloak.service';
|
||||
|
||||
export const authResolver: ResolveFn<boolean> = async (route, state) => {
|
||||
const keycloakService: KeycloakService = inject(KeycloakService);
|
||||
|
||||
if (!keycloakService.isLoggedIn()) {
|
||||
await keycloakService.login({
|
||||
redirectUri: window.location.href,
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { createLogger } from '../utils/utils';
|
||||
import { KeycloakService } from './keycloak.service';
|
||||
const logger = createLogger('KeycloakInitializerService');
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class KeycloakInitializerService {
|
||||
private initialized = false;
|
||||
|
||||
constructor(private keycloakService: KeycloakService) {}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const authenticated = await this.keycloakService.init({
|
||||
config: {
|
||||
url: environment.keycloak.url,
|
||||
realm: environment.keycloak.realm,
|
||||
clientId: environment.keycloak.clientId,
|
||||
},
|
||||
initOptions: {
|
||||
onLoad: 'check-sso',
|
||||
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
||||
},
|
||||
});
|
||||
|
||||
logger.info(`--->${authenticated}`);
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
isInitialized(): boolean {
|
||||
return this.initialized;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,16 +6,14 @@
|
|||
* found in the LICENSE file at https://github.com/mauriciovigolo/keycloak-angular/blob/main/LICENSE.md
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpHeaders, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import Keycloak from 'keycloak-js';
|
||||
import { Subject, from } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import Keycloak from 'keycloak-js';
|
||||
|
||||
|
||||
import { ExcludedUrl, ExcludedUrlRegex, KeycloakOptions } from '../models/keycloak-options';
|
||||
import { KeycloakEvent, KeycloakEventType } from '../models/keycloak-event';
|
||||
import { ExcludedUrl, ExcludedUrlRegex, KeycloakOptions } from '../models/keycloak-options';
|
||||
|
||||
/**
|
||||
* Service to expose existent methods from the Keycloak JS adapter, adding new
|
||||
|
|
@ -64,8 +62,7 @@ export class KeycloakService {
|
|||
/**
|
||||
* Observer for the keycloak events
|
||||
*/
|
||||
private _keycloakEvents$: Subject<KeycloakEvent> =
|
||||
new Subject<KeycloakEvent>();
|
||||
private _keycloakEvents$: Subject<KeycloakEvent> = new Subject<KeycloakEvent>();
|
||||
/**
|
||||
* The amount of required time remaining before expiry of the token before the token will be refreshed.
|
||||
*/
|
||||
|
|
@ -87,10 +84,10 @@ export class KeycloakService {
|
|||
* argument if the source function provides any.
|
||||
*/
|
||||
private bindsKeycloakEvents(): void {
|
||||
this._instance.onAuthError = (errorData) => {
|
||||
this._instance.onAuthError = errorData => {
|
||||
this._keycloakEvents$.next({
|
||||
args: errorData,
|
||||
type: KeycloakEventType.OnAuthError
|
||||
type: KeycloakEventType.OnAuthError,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -100,13 +97,13 @@ export class KeycloakService {
|
|||
|
||||
this._instance.onAuthRefreshSuccess = () => {
|
||||
this._keycloakEvents$.next({
|
||||
type: KeycloakEventType.OnAuthRefreshSuccess
|
||||
type: KeycloakEventType.OnAuthRefreshSuccess,
|
||||
});
|
||||
};
|
||||
|
||||
this._instance.onAuthRefreshError = () => {
|
||||
this._keycloakEvents$.next({
|
||||
type: KeycloakEventType.OnAuthRefreshError
|
||||
type: KeycloakEventType.OnAuthRefreshError,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -116,21 +113,21 @@ export class KeycloakService {
|
|||
|
||||
this._instance.onTokenExpired = () => {
|
||||
this._keycloakEvents$.next({
|
||||
type: KeycloakEventType.OnTokenExpired
|
||||
type: KeycloakEventType.OnTokenExpired,
|
||||
});
|
||||
};
|
||||
|
||||
this._instance.onActionUpdate = (state) => {
|
||||
this._instance.onActionUpdate = state => {
|
||||
this._keycloakEvents$.next({
|
||||
args: state,
|
||||
type: KeycloakEventType.OnActionUpdate
|
||||
type: KeycloakEventType.OnActionUpdate,
|
||||
});
|
||||
};
|
||||
|
||||
this._instance.onReady = (authenticated) => {
|
||||
this._instance.onReady = authenticated => {
|
||||
this._keycloakEvents$.next({
|
||||
args: authenticated,
|
||||
type: KeycloakEventType.OnReady
|
||||
type: KeycloakEventType.OnReady,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -142,9 +139,7 @@ export class KeycloakService {
|
|||
* @param bearerExcludedUrls array of strings or ExcludedUrl that includes
|
||||
* the url and HttpMethod.
|
||||
*/
|
||||
private loadExcludedUrls(
|
||||
bearerExcludedUrls: (string | ExcludedUrl)[]
|
||||
): ExcludedUrlRegex[] {
|
||||
private loadExcludedUrls(bearerExcludedUrls: (string | ExcludedUrl)[]): ExcludedUrlRegex[] {
|
||||
const excludedUrls: ExcludedUrlRegex[] = [];
|
||||
for (const item of bearerExcludedUrls) {
|
||||
let excludedUrl: ExcludedUrlRegex;
|
||||
|
|
@ -153,7 +148,7 @@ export class KeycloakService {
|
|||
} else {
|
||||
excludedUrl = {
|
||||
urlPattern: new RegExp(item.url, 'i'),
|
||||
httpMethods: item.httpMethods
|
||||
httpMethods: item.httpMethods,
|
||||
};
|
||||
}
|
||||
excludedUrls.push(excludedUrl);
|
||||
|
|
@ -175,7 +170,7 @@ export class KeycloakService {
|
|||
initOptions,
|
||||
updateMinValidity = 20,
|
||||
shouldAddToken = () => true,
|
||||
shouldUpdateToken = () => true
|
||||
shouldUpdateToken = () => true,
|
||||
}: KeycloakOptions): void {
|
||||
this._enableBearerInterceptor = enableBearerInterceptor;
|
||||
this._loadUserProfileAtStartUp = loadUserProfileAtStartUp;
|
||||
|
|
@ -285,7 +280,7 @@ export class KeycloakService {
|
|||
*/
|
||||
public async logout(redirectUri?: string) {
|
||||
const options = {
|
||||
redirectUri
|
||||
redirectUri,
|
||||
};
|
||||
|
||||
await this._instance.logout(options);
|
||||
|
|
@ -302,9 +297,7 @@ export class KeycloakService {
|
|||
* @returns
|
||||
* A void Promise if the register flow was successful.
|
||||
*/
|
||||
public async register(
|
||||
options: Keycloak.KeycloakLoginOptions = { action: 'register' }
|
||||
) {
|
||||
public async register(options: Keycloak.KeycloakLoginOptions = { action: 'register' }) {
|
||||
await this._instance.register(options);
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +338,7 @@ export class KeycloakService {
|
|||
let roles: string[] = [];
|
||||
|
||||
if (this._instance.resourceAccess) {
|
||||
Object.keys(this._instance.resourceAccess).forEach((key) => {
|
||||
Object.keys(this._instance.resourceAccess).forEach(key => {
|
||||
if (resource && resource !== key) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -407,9 +400,7 @@ export class KeycloakService {
|
|||
// is not implemented, avoiding the redirect loop.
|
||||
if (this._silentRefresh) {
|
||||
if (this.isTokenExpired()) {
|
||||
throw new Error(
|
||||
'Failed to refresh the token, or the session is expired'
|
||||
);
|
||||
throw new Error('Failed to refresh the token, or the session is expired');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -442,16 +433,14 @@ export class KeycloakService {
|
|||
}
|
||||
|
||||
if (!this._instance.authenticated) {
|
||||
throw new Error(
|
||||
'The user profile was not loaded as the user is not logged in.'
|
||||
);
|
||||
throw new Error('The user profile was not loaded as the user is not logged in.');
|
||||
}
|
||||
|
||||
return (this._userProfile = await this._instance.loadUserProfile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authenticated token, calling updateToken to get a refreshed one if necessary.
|
||||
* Returns the authenticated token.
|
||||
*/
|
||||
public async getToken() {
|
||||
return this._instance.token;
|
||||
|
|
@ -491,16 +480,7 @@ export class KeycloakService {
|
|||
* An observable with with the HTTP Authorization header and the current token.
|
||||
*/
|
||||
public addTokenToHeader(headers: HttpHeaders = new HttpHeaders()) {
|
||||
return from(this.getToken()).pipe(
|
||||
map((token) =>
|
||||
token
|
||||
? headers.set(
|
||||
this._authorizationHeaderName,
|
||||
this._bearerPrefix + token
|
||||
)
|
||||
: headers
|
||||
)
|
||||
);
|
||||
return from(this.getToken()).pipe(map(token => (token ? headers.set(this._authorizationHeaderName, this._bearerPrefix + token) : headers)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,107 +1,18 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable, Signal, computed, effect, signal } from '@angular/core';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { Observable, distinctUntilChanged, filter, from, lastValueFrom, map } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import urlcat from 'urlcat';
|
||||
import { User } from '../../../../bizmatch-server/src/models/db.model';
|
||||
import { JwtToken, KeycloakUser, ListingCriteria, ResponseUsersArray, StatesResult } from '../../../../bizmatch-server/src/models/main.model';
|
||||
import { ListingCriteria, ResponseUsersArray, StatesResult } from '../../../../bizmatch-server/src/models/main.model';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { KeycloakService } from './keycloak.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UserService {
|
||||
private apiBaseUrl = environment.apiBaseUrl;
|
||||
// -----------------------------
|
||||
// Keycloak services
|
||||
// -----------------------------
|
||||
private user$ = new Observable<KeycloakUser>();
|
||||
private user: KeycloakUser;
|
||||
public $isLoggedIn: Signal<boolean>;
|
||||
constructor(public keycloak: KeycloakService, private http: HttpClient) {
|
||||
this.user$ = from(this.keycloak.getToken()).pipe(
|
||||
filter(t => !!t),
|
||||
distinctUntilChanged(),
|
||||
map(t => this.map2User(t)),
|
||||
// tap(u => {
|
||||
// logger.info('Logged in user:', u);
|
||||
// this.analyticsService.identify(u);
|
||||
// }),
|
||||
);
|
||||
this.$isLoggedIn = signal(false);
|
||||
this.$isLoggedIn = computed(() => {
|
||||
return keycloak.isLoggedIn();
|
||||
});
|
||||
|
||||
effect(async () => {
|
||||
if (this.$isLoggedIn()) {
|
||||
this.updateTokenDetails();
|
||||
} else {
|
||||
this.user = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async refreshToken(): Promise<void> {
|
||||
try {
|
||||
await this.keycloak.updateToken(10); // Versuche, den Token zu erneuern
|
||||
await this.updateTokenDetails(); // Aktualisiere den Token und seine Details
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Token-Refresh', error);
|
||||
}
|
||||
}
|
||||
private async updateTokenDetails(): Promise<void> {
|
||||
const token = await this.keycloak.getToken();
|
||||
this.user = this.map2User(token);
|
||||
}
|
||||
|
||||
private map2User(jwt: string): KeycloakUser {
|
||||
const token = jwtDecode<JwtToken>(jwt);
|
||||
return {
|
||||
id: token.user_id,
|
||||
firstName: token.given_name,
|
||||
lastName: token.family_name,
|
||||
email: token.email,
|
||||
};
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.$isLoggedIn();
|
||||
}
|
||||
getKeycloakUser(): KeycloakUser {
|
||||
return this.user;
|
||||
}
|
||||
getUserObservable(): Observable<KeycloakUser> {
|
||||
return this.user$;
|
||||
}
|
||||
async getId(): Promise<string> {
|
||||
if (sessionStorage.getItem('USERID')) {
|
||||
return sessionStorage.getItem('USERID');
|
||||
} else {
|
||||
const user = await this.getByMail(this.user.email);
|
||||
sessionStorage.setItem('USERID', user.id);
|
||||
return user.id;
|
||||
}
|
||||
}
|
||||
logout() {
|
||||
sessionStorage.removeItem('USERID');
|
||||
this.keycloak.logout(window.location.origin + '/home');
|
||||
}
|
||||
async login(url: string) {
|
||||
await this.keycloak.login({
|
||||
redirectUri: url,
|
||||
});
|
||||
}
|
||||
getUserRoles() {
|
||||
return this.keycloak.getUserRoles(true);
|
||||
}
|
||||
hasAdminRole() {
|
||||
return this.keycloak.getUserRoles(true).includes('ADMIN');
|
||||
}
|
||||
register(url: string) {
|
||||
this.keycloak.register({ redirectUri: url });
|
||||
}
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
// -----------------------------
|
||||
// DB services
|
||||
|
|
@ -122,4 +33,13 @@ export class UserService {
|
|||
async getAllStates(): Promise<any> {
|
||||
return await lastValueFrom(this.http.get<StatesResult[]>(`${this.apiBaseUrl}/bizmatch/user/states/all`));
|
||||
}
|
||||
async getId(email: string): Promise<string> {
|
||||
if (sessionStorage.getItem('USERID')) {
|
||||
return sessionStorage.getItem('USERID');
|
||||
} else {
|
||||
const user = await this.getByMail(email);
|
||||
sessionStorage.setItem('USERID', user.id);
|
||||
return user.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Router } from '@angular/router';
|
||||
import { ConsoleFormattedStream, INFO, createLogger as _createLogger, stdSerializers } from 'browser-bunyan';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { BusinessListing, CommercialPropertyListing } from '../../../../bizmatch-server/src/models/db.model';
|
||||
import { ListingCriteria } from '../../../../bizmatch-server/src/models/main.model';
|
||||
import { JwtToken, KeycloakUser, ListingCriteria } from '../../../../bizmatch-server/src/models/main.model';
|
||||
|
||||
export function createDefaultCommercialPropertyListing(): CommercialPropertyListing {
|
||||
return {
|
||||
|
|
@ -116,3 +117,16 @@ export function resetCriteria(criteria: ListingCriteria) {
|
|||
criteria.title = null;
|
||||
criteria.name = null;
|
||||
}
|
||||
export function map2User(jwt: string): KeycloakUser {
|
||||
if (jwt) {
|
||||
const token = jwtDecode<JwtToken>(jwt);
|
||||
return {
|
||||
id: token.user_id,
|
||||
firstName: token.given_name,
|
||||
lastName: token.family_name,
|
||||
email: token.email,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue