added tenant code to url

This commit is contained in:
Diamantis Tziotzios 2024-06-06 17:31:20 +03:00
parent db25687dd5
commit a4df13a051
18 changed files with 306 additions and 213 deletions

View File

@ -3,12 +3,11 @@ import { RouterModule, Routes } from '@angular/router';
import { AppPermission } from './core/common/enum/permission.enum';
import { BreadcrumbService } from './ui/misc/breadcrumb/breadcrumb.service';
import { ReloadHelperComponent } from './ui/misc/reload-helper/reload-helper.component';
import { DepositOauth2DialogComponent } from './ui/misc/deposit-oauth2-dialog/deposit-oauth2-dialog.component';
const appRoutes: Routes = [
{
path: '',
redirectTo:'home',
redirectTo: 'home',
pathMatch: 'full'
},
{
@ -35,7 +34,7 @@ const appRoutes: Routes = [
},
{
path: 'explore-descriptions',
loadChildren: () => import('./ui/description/description.module').then(m => m.DescriptionModule),
loadChildren: () => import('./ui/description/description.module').then(m => m.PublicDescriptionModule),
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -60,7 +59,7 @@ const appRoutes: Routes = [
},
{
path: 'explore-plans',
loadChildren: () => import('./ui/dmp/dmp.module').then(m => m.DmpModule),
loadChildren: () => import('./ui/dmp/dmp.module').then(m => m.PublicDmpModule),
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -183,14 +182,6 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.COOKIES-POLICY'
}
},
// {
// path: 'splash',
// loadChildren: () => import('./ui/splash/splash.module').then(m => m.SplashModule),
// data: {
// breadcrumb: true
// }
// },
{
path: 'unauthorized',
loadChildren: () => import('./ui/misc/unauthorized/unauthorized.module').then(m => m.UnauthorizedModule),
@ -387,8 +378,18 @@ const appRoutes: Routes = [
}
];
const tenantEnrichedRoutes: Routes = [
{
path: 't/:tenant_code',
children: [
...appRoutes
]
},
...appRoutes
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes, {})],
imports: [RouterModule.forRoot(tenantEnrichedRoutes, {})],
exports: [RouterModule],
})
export class AppRoutingModule { }

View File

@ -3,7 +3,7 @@ import { of as observableOf, Subscription } from 'rxjs';
import { switchMap, filter, map, takeUntil } from 'rxjs/operators';
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { ActivatedRoute, NavigationEnd, NavigationStart, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { AuthService, LoginStatus } from './core/services/auth/auth.service';
import { CultureService } from './core/services/culture/culture-service';
@ -23,6 +23,7 @@ import { TenantConfigurationService } from './core/services/tenant-configuration
import { TenantConfigurationType } from './core/common/enum/tenant-configuration-type';
import { CssColorsTenantConfiguration, TenantConfiguration } from './core/model/tenant-configuaration/tenant-configuration';
import { nameof } from 'ts-simple-nameof';
import { TenantHandlingService } from './core/services/tenant/tenant-handling.service';
declare const gapi: any;
@ -43,7 +44,7 @@ export class AppComponent implements OnInit, AfterViewInit {
onlySplash = true;
showOnlyRouterOutlet = false;
@ViewChild('sidenav') sidenav:MatSidenav;
@ViewChild('sidenav') sidenav: MatSidenav;
constructor(
private router: Router,
@ -61,7 +62,8 @@ export class AppComponent implements OnInit, AfterViewInit {
private location: Location,
private matomoService: MatomoService,
private tenantConfigurationService: TenantConfigurationService,
private sidenavService: SideNavService
private sidenavService: SideNavService,
private tenantHandlingService: TenantHandlingService
) {
this.initializeServices();
this.matomoService.init();
@ -69,30 +71,30 @@ export class AppComponent implements OnInit, AfterViewInit {
}
ngAfterViewInit(): void {
setTimeout(() => {
this.sideNavSubscription = this.sidenavService.status().subscribe(isopen=>{
this.sideNavSubscription = this.sidenavService.status().subscribe(isopen => {
const hamburger = document.getElementById('hamburger');
if(isopen){
if (isopen) {
//update value of hamburfer
if(!hamburger){//try later
if (!hamburger) {//try later
setTimeout(() => {
const hamburger = document.getElementById('hamburger');
if(hamburger){
const hamburger = document.getElementById('hamburger');
if (hamburger) {
hamburger.classList.add('change');
}
}, 300);
}else{
} else {
hamburger.classList.add('change');
}
this.sidenav.open()
}else{//closed
if(!hamburger){//try later
} else {//closed
if (!hamburger) {//try later
setTimeout(() => {
const hamburger = document.getElementById('hamburger');
if(hamburger){
const hamburger = document.getElementById('hamburger');
if (hamburger) {
hamburger.classList.remove('change');
}
}, 300);
}else{
} else {
hamburger.classList.remove('change');
}
this.sidenav.close();
@ -114,7 +116,7 @@ export class AppComponent implements OnInit, AfterViewInit {
if (this.location.path() === '') {
if (!this.configurationService.useSplash) {
this.onlySplash = false;
this.router.navigate(['/reload']).then(() => this.router.navigate(['/home']));
this.router.navigate(['/home']);
} else {
this.onlySplash = true;
this.router.navigate(['/reload']).then(() => this.router.navigate(['/splash']));
@ -126,7 +128,7 @@ export class AppComponent implements OnInit, AfterViewInit {
}
if (!this.cookieService.check("cookiesConsent")) {
// this.cookieService.set("cookiesConsent", "false", 356);
this.cookieService.set("cookiesConsent", "false", 356,null,null,false, 'Lax');
this.cookieService.set("cookiesConsent", "false", 356, null, null, false, 'Lax');
}
@ -171,17 +173,32 @@ export class AppComponent implements OnInit, AfterViewInit {
return { title: child.snapshot.data['title'], usePrefix: usePrefix };
}
}
return { title: appTitle, usePrefix: true};
return { title: appTitle, usePrefix: true };
})
).subscribe((titleOptions: { title: string, usePrefix: boolean}) => {
).subscribe((titleOptions: { title: string, usePrefix: boolean }) => {
this.translateTitle(titleOptions.title, titleOptions.usePrefix);
this.translate.onLangChange.subscribe(() => this.translateTitle(titleOptions.title, titleOptions.usePrefix));
});
this.router
.events.pipe(
filter(event => event instanceof NavigationEnd)
)
.subscribe((event: NavigationStart) => {
const enrichedUrl = this.tenantHandlingService.getUrlEnrichedWithTenantCode(event.url, this.authentication.selectedTenant() ?? 'default');
if (event.url != enrichedUrl) {
this.router.navigate([enrichedUrl]);
console.log('enriched')
console.log(event.url)
console.log(enrichedUrl)
}
});
this.statusChangeSubscription = this.ccService.statusChange$.subscribe((event: NgcStatusChangeEvent) => {
if (event.status == "dismiss") {
// this.cookieService.set("cookiesConsent", "true", 365);
this.cookieService.set("cookiesConsent", "true", 356,null,null,false, 'Lax');
this.cookieService.set("cookiesConsent", "true", 356, null, null, false, 'Lax');
}
});
@ -203,7 +220,7 @@ export class AppComponent implements OnInit, AfterViewInit {
}
this.ccService.destroy();
this.ccService.init(this.ccService.getConfig());
});
});
}
translateTitle(ttl: string, usePrefix: boolean) {
@ -226,7 +243,7 @@ export class AppComponent implements OnInit, AfterViewInit {
ngOnDestroy() {
this.statusChangeSubscription.unsubscribe();
if(this.sideNavSubscription){
if (this.sideNavSubscription) {
this.sideNavSubscription.unsubscribe();
}
}
@ -269,24 +286,24 @@ export class AppComponent implements OnInit, AfterViewInit {
private loadCssColors() {
if (this.authentication.currentAccountIsAuthenticated() && this.authentication.selectedTenant()) {
this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.CssColors, [
this.tenantConfigurationService.getCurrentTenantType(TenantConfigurationType.CssColors, [
nameof<TenantConfiguration>(x => x.type),
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor)].join('.'),
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor2)].join('.'),
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.primaryColor3)].join('.'),
[nameof<TenantConfiguration>(x => x.cssColors), nameof<CssColorsTenantConfiguration>(x => x.secondaryColor)].join('.'),
])
.pipe(map(data => data as TenantConfiguration))
.subscribe(
data => {
if (data?.cssColors) {
if (data.cssColors.primaryColor) document.documentElement.style.setProperty(`--primary-color`, data.cssColors.primaryColor);
if (data.cssColors.primaryColor2) document.documentElement.style.setProperty(`--primary-color-2`, data.cssColors.primaryColor2);
if (data.cssColors.primaryColor3) document.documentElement.style.setProperty(`--primary-color-3`, data.cssColors.primaryColor3);
if (data.cssColors.secondaryColor) document.documentElement.style.setProperty(`--secondary-color`, data.cssColors.secondaryColor);
}
},
);
.pipe(map(data => data as TenantConfiguration))
.subscribe(
data => {
if (data?.cssColors) {
if (data.cssColors.primaryColor) document.documentElement.style.setProperty(`--primary-color`, data.cssColors.primaryColor);
if (data.cssColors.primaryColor2) document.documentElement.style.setProperty(`--primary-color-2`, data.cssColors.primaryColor2);
if (data.cssColors.primaryColor3) document.documentElement.style.setProperty(`--primary-color-3`, data.cssColors.primaryColor3);
if (data.cssColors.secondaryColor) document.documentElement.style.setProperty(`--secondary-color`, data.cssColors.secondaryColor);
}
},
);
}
}

View File

@ -41,6 +41,7 @@ import { CoreAnnotationServiceModule } from 'annotation-service/services/core-se
import { CoreNotificationServiceModule } from '@notification-service/services/core-service.module';
import { DepositOauth2DialogModule } from './ui/misc/deposit-oauth2-dialog/deposit-oauth2-dialog.module';
import { AnalyticsService } from './core/services/matomo/analytics-service';
import { TenantHandlingService } from './core/services/tenant/tenant-handling.service';
// AoT requires an exported function for factories
export function HttpLoaderFactory(languageHttpService: LanguageHttpService) {
@ -82,7 +83,7 @@ const appearance: MatFormFieldDefaultOptions = {
// appearance: 'standard'
};
export function InstallationConfigurationFactory(appConfig: ConfigurationService, keycloak: KeycloakService, authService: AuthService, languageService: LanguageService) {
export function InstallationConfigurationFactory(appConfig: ConfigurationService, keycloak: KeycloakService, authService: AuthService, languageService: LanguageService, tenantHandlingService:TenantHandlingService) {
return () => appConfig.loadConfiguration().then(() => {
return languageService.loadAvailableLanguages().toPromise();
}).then(x => keycloak.init({
@ -109,8 +110,10 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService
InterceptorType.UnauthorizedResponse,
]
};
const tenantCode = tenantHandlingService.extractTenantCodeFromUrlPath(window.location.pathname) ?? authService.selectedTenant() ?? 'default';
const tokenPromise = keycloak.getToken();
return authService.prepareAuthRequest(from(tokenPromise), { params }).toPromise().catch(error => authService.onAuthenticateError(error));
return authService.prepareAuthRequest(from(tokenPromise), tenantCode, { params }).toPromise().catch(error => authService.onAuthenticateError(error));
}));
}

View File

@ -45,6 +45,7 @@ import { VisibilityRulesService } from '@app/ui/description/editor/description-f
import { StorageFileService } from './services/storage-file/storage-file.service';
import { TenantConfigurationService } from './services/tenant-configuration/tenant-configuration.service';
import { DefaultUserLocaleService } from './services/default-user-locale/default-user-locale.service';
import { TenantHandlingService } from './services/tenant/tenant-handling.service';
//
//
// This is shared module that provides all the services. Its imported only once on the AppModule.
@ -109,7 +110,8 @@ export class CoreServiceModule {
PrefillingSourceService,
VisibilityRulesService,
TenantConfigurationService,
StorageFileService
StorageFileService,
TenantHandlingService
],
};
}

View File

@ -154,11 +154,11 @@ export class AuthService extends BaseService {
public isLoggedIn(): boolean {
return this.authState();
}
public prepareAuthRequest(observable: Observable<string>, httpParams?: Object): Observable<boolean> {
public prepareAuthRequest(observable: Observable<string>, tenantCode: string, httpParams?: Object): Observable<boolean> {
return observable.pipe(
map((x) => this.currentAuthenticationToken(x)),
exhaustMap(() => forkJoin([
this.accessToken ? this.ensureTenant() : of(false),
this.accessToken ? this.ensureTenant(tenantCode ?? this.selectedTenant() ?? 'default') : of(false),
this.accessToken ? this.principalService.me(httpParams) : of(null),
])),
map((item) => {
@ -176,10 +176,10 @@ export class AuthService extends BaseService {
);
}
public ensureTenant(): Observable<string> {
if (!this.selectedTenant()) {
this.selectedTenant('default');
}
private ensureTenant(tenantCode: string): Observable<string> {
// if (!this.selectedTenant()) {
// this.selectedTenant('default');
// }
const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.TenantHeaderInterceptor]
@ -188,16 +188,21 @@ export class AuthService extends BaseService {
map(
(myTenants) => {
if (myTenants) {
if (this.selectedTenant()) {
if (myTenants.findIndex(x => x.code.toLocaleLowerCase() == this.selectedTenant().toLocaleLowerCase()) < 0) {
this.selectedTenant(null);
}
}
if (!this.selectedTenant()) {
if (myTenants.length > 0) {
this.selectedTenant(myTenants[0]?.code);
}
if (myTenants.some(x => x.code.toLocaleLowerCase() == tenantCode.toLocaleLowerCase())) {
this.selectedTenant(tenantCode);
} else {
this.selectedTenant(null);
}
// if (this.selectedTenant()) {
// if (myTenants.findIndex(x => x.code.toLocaleLowerCase() == this.selectedTenant().toLocaleLowerCase()) < 0) {
// this.selectedTenant(null);
// }
// }
// if (!this.selectedTenant()) {
// if (myTenants.length > 0) {
// this.selectedTenant(myTenants[0]?.code);
// }
// }
} else {
this.selectedTenant(null);
}
@ -326,6 +331,7 @@ export class AuthService extends BaseService {
return this.prepareAuthRequest(
from(this.keycloakService.getToken()),
this.selectedTenant(),
httpParams
)
.pipe(takeUntil(this._destroyed))

View File

@ -57,21 +57,34 @@ export class CultureService {
// Set angular locale based on user selection.
// This is a very hacky way to map cultures with angular cultures, since there is no mapping. We first try to
// use the culture with the specialization (ex en-US), and if not exists we import the base culture (first part).
let locale = newCulture.name;
import(`/node_modules/@angular/common/locales/${locale}.mjs`).catch(reason => {
this.logger.error('Could not load locale: ' + locale);
}).then(selectedLocale => {
if (selectedLocale) {
registerLocaleData(selectedLocale.default);
} else {
locale = newCulture.name.split('-')[0];
import(`/node_modules/@angular/common/locales/${locale}.mjs`).catch(reason => {
this.logger.error('Could not load locale: ' + locale);
}).then(selectedDefaultLocale => {
registerLocaleData(selectedDefaultLocale.default);
});
}
});
// let locale = newCulture.name;
// const base = import(
// /* webpackExclude: /\.d\.ts$/ */
// /* webpackMode: "lazy-once" */
// /* webpackChunkName: "i18n-base" */
// `@angular/common/locales/${locale}.mjs`)//.then(m => m[basePkg]);
// const extra = import(
// /* webpackExclude: /\.d\.ts$/ */
// /* webpackMode: "lazy-once" */
// /* webpackChunkName: "i18n-extra" */
// `@angular/common/locales/extra/${locale.split('-')[0]}.mjs`)//.then(m => m[extraPkg]);
// import(`/node_modules/ @angular/common/locales/${locale}.mjs`).catch(reason => {
// this.logger.error('Could not load locale: ' + locale);
// }).then(selectedLocale => {
// if (selectedLocale) {
// registerLocaleData(selectedLocale.default);
// } else {
// locale = newCulture.name.split('-')[0];
// import(`/node_modules/@angular/common/locales/${locale}.mjs`).catch(reason => {
// this.logger.error('Could not load locale: ' + locale);
// }).then(selectedDefaultLocale => {
// registerLocaleData(selectedDefaultLocale.default);
// });
// }
// });
}
getCultureChangeObservable(): Observable<CultureInfo> {

View File

@ -0,0 +1,58 @@
import { DOCUMENT, LocationStrategy } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { PRIMARY_OUTLET, Router, UrlSegment, UrlSegmentGroup, UrlTree } from '@angular/router';
@Injectable()
export class TenantHandlingService {
constructor(
@Inject(DOCUMENT) private readonly document: Document,
private readonly locationStrategy: LocationStrategy,
private readonly router: Router,
) {
}
extractTenantCodeFromUrlPath(path: string): string {
//Searches for "/t/<tenant_code>/" in a url;
const tenantRegex = new RegExp("\/t\/([^\/]+)");
const regexResult = tenantRegex.exec(path);
let tenantCode = null;
if (Array.isArray(regexResult) && regexResult.length > 0) {
tenantCode = regexResult[1];
}
return tenantCode;
}
getCurrentUrlEnrichedWithTenantCode(tenantCode: string, withOrigin: boolean) {
const path = this.getUrlEnrichedWithTenantCode(this.router.routerState.snapshot.url, tenantCode)
return withOrigin ? this.getBaseUrl() + path.substring(1) : path;
}
getUrlEnrichedWithTenantCode(url: string, tenantCode: string) {
const urlTree: UrlTree = this.router.parseUrl(url);
const urlSegmentGroup: UrlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
const urlSegments: UrlSegment[] = urlSegmentGroup.segments;
const tenantParamIndex = urlSegments.findIndex(x => x.path == 't');
if (tenantParamIndex >= 0) {
if (tenantCode == 'default') {
urlSegments.splice(tenantParamIndex, 2);
} else {
const tenantCodeSegment = urlSegments.at(tenantParamIndex + 1);
tenantCodeSegment.path = tenantCode;
}
} else {
if (tenantCode != 'default') {
urlTree.root.children[PRIMARY_OUTLET].segments = [new UrlSegment('t', {}), new UrlSegment(tenantCode, {}), ...urlSegments];
}
}
return urlTree.toString();
}
getBaseUrl(): string {
return this.document.location.origin + this.locationStrategy.getBaseHref();
}
}

View File

@ -31,13 +31,13 @@
<div style="position: relative;" class="col-12" *ngIf="hasFocus" [@fade-in]>
<div *ngIf="showDescription" class="mb-4">
<h5 style="font-weight: bold" class="row">{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.DESCRIPTION' | translate}}</h5>
<rich-text-editor-component [form]="form.get('description')" [id]="'editor1'" [placeholder]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.DESCRIPTION'" [wrapperClasses]="'row'" [editable]="!viewOnly">
<rich-text-editor-component [form]="form.get('description')" [placeholder]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.DESCRIPTION'" [wrapperClasses]="'row'" [editable]="!viewOnly">
</rich-text-editor-component>
<mat-error *ngIf="this.form.get('description').hasError('backendError')">{{form.get('description').getError('backendError').message}}</mat-error>
</div>
<div *ngIf="showExtendedDescription" class="mb-4">
<h5 style="font-weight: bold" class="row">{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.EXTENDED-DESCRIPTION' | translate}}</h5>
<rich-text-editor-component [form]="form.get('extendedDescription')" [id]="'editor2'" [placeholder]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.EXTENDED-DESCRIPTION'" [wrapperClasses]="'row'" [editable]="!viewOnly">
<rich-text-editor-component [form]="form.get('extendedDescription')" [placeholder]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.EXTENDED-DESCRIPTION'" [wrapperClasses]="'row'" [editable]="!viewOnly">
</rich-text-editor-component>
<mat-error *ngIf="this.form.get('extendedDescription').hasError('backendError')">{{form.get('extendedDescription').getError('backendError').message}}</mat-error>
</div>

View File

@ -1,10 +1,8 @@
import { Component, Input, NgZone, OnInit } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '@app/core/services/auth/auth.service';
import { PrincipalService } from '@app/core/services/http/principal.service';
import { TenantHandlingService } from '@app/core/services/tenant/tenant-handling.service';
import { BaseComponent } from '@common/base/base.component';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { KeycloakService } from 'keycloak-angular';
import { from } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -27,7 +25,7 @@ export class LoginComponent extends BaseComponent implements OnInit {
private router: Router,
private authService: AuthService,
private route: ActivatedRoute,
private principalService: PrincipalService,
private tenantHandlingService: TenantHandlingService,
private keycloakService: KeycloakService
) { super(); }
@ -36,7 +34,8 @@ export class LoginComponent extends BaseComponent implements OnInit {
if (!this.keycloakService.isLoggedIn()) {
this.authService.authenticate(this.returnUrl);
} else {
this.authService.prepareAuthRequest(from(this.keycloakService.getToken())).pipe(takeUntil(this._destroyed)).subscribe(
const tenantCode = this.tenantHandlingService.extractTenantCodeFromUrlPath(this.returnUrl) ?? this.authService.selectedTenant() ?? 'default';
this.authService.prepareAuthRequest(from(this.keycloakService.getToken()), tenantCode).pipe(takeUntil(this._destroyed)).subscribe(
() => {
let returnUrL = this.returnUrl;
this.zone.run(() => this.router.navigateByUrl(returnUrL));

View File

@ -15,13 +15,10 @@ export class LogoutComponent implements OnInit {
ngOnInit() {
this.authService.clear();
debugger;
this.keycloak.logout(location.origin).then(() => {
localStorage.clear();
// this.router.navigate(['./'], { replaceUrl: true });
});
// this.tokenService.logout(() => {
// localStorage.clear();
// this.router.navigate(["./"], { replaceUrl: true });
// });
}
}

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
import { DescriptionRoutingModule } from '@app/ui/description/description.routing';
import { DescriptionRoutingModule, PublicDescriptionRoutingModule } from '@app/ui/description/description.routing';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
@ -17,3 +17,17 @@ import { CommonUiModule } from '@common/ui/common-ui.module';
]
})
export class DescriptionModule { }
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
FormattingModule,
PublicDescriptionRoutingModule,
],
declarations: [
],
exports: [
]
})
export class PublicDescriptionModule { }

View File

@ -1,13 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '@app/core/auth-guard.service';
import { BreadcrumbService } from '../misc/breadcrumb/breadcrumb.service';
// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component';
// import { DescriptionOverviewComponent } from './overview/description-overview.component';
const routes: Routes = [
{
path: 'overview',
loadChildren: () => import('./overview/description-overview.module').then(m => m.DescriptionOverviewModule),
canActivate: [AuthGuard],
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -18,6 +18,28 @@ const routes: Routes = [
{
path: 'edit',
loadChildren: () => import('./editor/description-editor.module').then(m => m.DescriptionEditorModule),
canActivate: [AuthGuard],
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
hideNavigationItem: true
}),
}
},
{
path: '',
canActivate: [AuthGuard],
loadChildren: () => import('./listing/description-listing.module').then(m => m.DescriptionListingModule),
data: {
breadcrumb: true
},
},
];
const publicRoutes: Routes = [
{
path: 'overview',
loadChildren: () => import('./overview/description-overview.module').then(m => m.DescriptionOverviewModule),
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -40,3 +62,10 @@ const routes: Routes = [
providers: []
})
export class DescriptionRoutingModule { }
@NgModule({
imports: [RouterModule.forChild(publicRoutes)],
exports: [RouterModule],
providers: []
})
export class PublicDescriptionRoutingModule { }

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
import { DmpRoutingModule } from '@app/ui/dmp/dmp.routing';
import { DmpRoutingModule, PublicDmpRoutingModule } from '@app/ui/dmp/dmp.routing';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
@ -17,3 +17,17 @@ import { CommonUiModule } from '@common/ui/common-ui.module';
]
})
export class DmpModule { }
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
FormattingModule,
PublicDmpRoutingModule,
],
declarations: [
],
exports: [
]
})
export class PublicDmpModule { }

View File

@ -1,11 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BreadcrumbService } from '../misc/breadcrumb/breadcrumb.service';
import { AuthGuard } from '@app/core/auth-guard.service';
const routes: Routes = [
{
path: 'overview',
loadChildren: () => import('./overview/dmp-overview.module').then(m => m.DmpOverviewModule),
canActivate:[AuthGuard],
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -16,6 +18,7 @@ const routes: Routes = [
{
path: 'new',
loadChildren: () => import('./dmp-editor-blueprint/dmp-editor.module').then(m => m.DmpEditorModule),
canActivate:[AuthGuard],
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -27,6 +30,7 @@ const routes: Routes = [
{
path: 'edit',
loadChildren: () => import('./dmp-editor-blueprint/dmp-editor.module').then(m => m.DmpEditorModule),
canActivate:[AuthGuard],
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
@ -37,80 +41,32 @@ const routes: Routes = [
},
{
path: '',
canActivate:[AuthGuard],
loadChildren: () => import('./listing/dmp-listing.module').then(m => m.DmpListingModule),
data: {
breadcrumb: true
},
},
];
// {
// path: 'publicEdit/:publicId',
// component: DmpEditorComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-PUBLIC-EDIT'
// },
// canDeactivate: [CanDeactivateGuard]
// },
// {
// path: 'publicOverview/:publicId',
// component: DmpOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-OVERVIEW'
// },
// },
// {
// path: 'new/dataset',
// component: DmpEditorComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumbs: 'new/dataset',
// title: 'GENERAL.TITLES.DATASET-NEW'
// }
// },
// {
// path: 'new/dataset/:dmpId',
// component: DmpEditorComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumbs: 'new/dataset',
// title: 'GENERAL.TITLES.DATASET-NEW'
// }
// },
// {
// path: 'new_version/:id',
// // component: DmpWizardComponent,
// component: DmpCloneComponent,
// data: {
// clone: false,
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-NEW-VERSION'
// },
// },
// {
// path: 'clone/:id',
// component: DmpCloneComponent,
// data: {
// clone: false,
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-CLONE'
// },
// },
// {
// path: 'invitation/:id',
// component: InvitationAcceptedComponent,
// data: {
// breadcrumb: true
// },
// }
const publicRoutes: Routes = [
{
path: 'overview',
loadChildren: () => import('./overview/dmp-overview.module').then(m => m.DmpOverviewModule),
data: {
breadcrumb: true,
...BreadcrumbService.generateRouteDataConfiguration({
hideNavigationItem: true
}),
}
},
{
path: '',
loadChildren: () => import('./listing/dmp-listing.module').then(m => m.DmpListingModule),
data: {
breadcrumb: true
},
},
];
@NgModule({
@ -118,3 +74,9 @@ const routes: Routes = [
exports: [RouterModule]
})
export class DmpRoutingModule { }
@NgModule({
imports: [RouterModule.forChild(publicRoutes)],
exports: [RouterModule]
})
export class PublicDmpRoutingModule { }

View File

@ -90,14 +90,20 @@ export class NavbarComponent extends BaseComponent implements OnInit {
this.authentication.getAuthenticationStateObservable().subscribe(authenticationState => {
if (authenticationState.loginStatus === LoginStatus.LoggedIn) {
this.loadLogo();
this.loadUser();
}
});
this.loadLogo();
this.loadUser();
}
this.userService.getSingle(this.authentication.userId(), [
nameof<User>(x => x.id),
nameof<User>(x => x.name)
]).subscribe(u => this.userName = u.name); //TODO HANDLE-ERRORS
private loadUser() {
if (this.authentication.currentAccountIsAuthenticated() && this.authentication.userId()) {
this.userService.getSingle(this.authentication.userId(), [
nameof<User>(x => x.id),
nameof<User>(x => x.name)
]).subscribe(u => this.userName = u.name); //TODO HANDLE-ERRORS
}
}
private loadLogo() {

View File

@ -1,15 +1,13 @@
import { Component, EventEmitter, OnInit, Output } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { MatButtonToggleChange } from "@angular/material/button-toggle";
import { Router } from "@angular/router";
import { Tenant } from "@app/core/model/tenant/tenant";
import { AuthService } from "@app/core/services/auth/auth.service";
import { PrincipalService } from "@app/core/services/http/principal.service";
import { TenantHandlingService } from "@app/core/services/tenant/tenant-handling.service";
import { BaseComponent } from "@common/base/base.component";
import { BaseHttpParams } from "@common/http/base-http-params";
import { InterceptorType } from "@common/http/interceptors/interceptor-type";
import { KeycloakService } from "keycloak-angular";
import { Observable, from } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { Observable } from "rxjs";
@Component({
selector: 'app-tenant-switch',
@ -20,10 +18,9 @@ export class TenantSwitchComponent extends BaseComponent implements OnInit {
tenants: Observable<Array<Tenant>>;
constructor(
private router: Router,
private keycloakService: KeycloakService,
private principalService: PrincipalService,
private authService: AuthService,
private tenantHandlingService: TenantHandlingService
) {
super();
}
@ -34,7 +31,6 @@ export class TenantSwitchComponent extends BaseComponent implements OnInit {
ngOnInit() {
this.tenants = this.loadUserTenants(); //TODO
//this.tenantChange.emit(this.getCurrentLanguage())
}
loadUserTenants(): Observable<Array<Tenant>> {
@ -48,22 +44,7 @@ export class TenantSwitchComponent extends BaseComponent implements OnInit {
onTenantSelected(selectedTenant: MatButtonToggleChange) {
if (selectedTenant.value === undefined || selectedTenant.value === '') return;
this.formSubmit(selectedTenant.value);
this.loadUser();
}
formSubmit(selectedTenant: string): void {
this.authService.selectedTenant(selectedTenant);
}
loadUser(): void {
this.authService.prepareAuthRequest(from(this.keycloakService.getToken()), {})
.pipe(takeUntil(this._destroyed))
.subscribe(
() => {
this.authService.onAuthenticateSuccessReload();
},
(error) => this.authService.onAuthenticateError(error)
);
this.authService.selectedTenant(selectedTenant.value);
window.location.href = this.tenantHandlingService.getCurrentUrlEnrichedWithTenantCode(selectedTenant.value, true);
}
}

View File

@ -1,4 +1,3 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
@ -18,6 +17,7 @@ import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service';
import { ReferenceService } from '@app/core/services/reference/reference.service';
import { TenantHandlingService } from '@app/core/services/tenant/tenant-handling.service';
import { UserService } from '@app/core/services/user/user.service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
@ -28,16 +28,15 @@ import { FormValidationErrorsDialogComponent } from '@common/forms/form-validati
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { KeycloakService } from 'keycloak-angular';
import * as moment from 'moment-timezone';
import { Observable, from, of } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { AddAccountDialogComponent } from './add-account/add-account-dialog.component';
import { UserProfileEditorModel } from './user-profile-editor.model';
import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
@Component({
selector: 'app-user-profile',
@ -81,7 +80,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
private dialog: MatDialog,
public enumUtils: EnumUtils,
private formBuilder: UntypedFormBuilder,
private keycloakService: KeycloakService,
private tenantHandlingService: TenantHandlingService,
private principalService: PrincipalService,
private formService: FormService,
private referenceService: ReferenceService,
@ -281,7 +280,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
}, maxWidth: '30em'
});
},
error => this.httpErrorHandlingService.handleBackedRequestError(error));
error => this.httpErrorHandlingService.handleBackedRequestError(error));
}
});
}
@ -309,7 +308,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
});
}
},
error => this.httpErrorHandlingService.handleBackedRequestError(error)); //TODO how to handle this
error => this.httpErrorHandlingService.handleBackedRequestError(error)); //TODO how to handle this
}
});
}
@ -367,17 +366,9 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
if (this.tenantFormGroup.valid === false) return;
const selectedTenant = this.tenantFormGroup.get('tenantCode').value;
this.formSubmit(selectedTenant);
this.loadUser();
}
formSubmit(selectedTenant: string): void {
this.authService.selectedTenant(selectedTenant);
}
loadUser(): void {
const returnUrl = '/profile';
this.authService.prepareAuthRequest(from(this.keycloakService.getToken()), {}).pipe(takeUntil(this._destroyed)).subscribe(() => this.authService.onAuthenticateSuccess(returnUrl), (error) => this.authService.onAuthenticateError(error));
this.authService.selectedTenant(selectedTenant.value);
window.location.href = this.tenantHandlingService.getCurrentUrlEnrichedWithTenantCode(selectedTenant.value, true);
}
//Preferences

View File

@ -43,13 +43,13 @@ export class UnauthorizedResponseInterceptor extends BaseInterceptor {
this.authService.refreshToken().then((isRefreshed) => {
this.accountRefresh$ = null;
if (!isRefreshed) {
this.logoutUser();
this.handleUnauthorized();
return false;
}
return true;
}).catch(x => {
this.logoutUser();
this.handleUnauthorized();
return false;
})
).pipe(filter((x) => x));
@ -67,10 +67,10 @@ export class UnauthorizedResponseInterceptor extends BaseInterceptor {
return next.handle(newRequest);
}
private logoutUser() {
private handleUnauthorized() {
if (!this.isLoginRoute() && !this.isSignupRoute()) {
this.authService.clear();
this.router.navigate(['/unauthorized']);
this.router.navigate(['/unauthorized', { queryParams: { returnUrl: this.router.url } }]);
}
}