From 53054e09711780dcff5797a9f23d47cf78e3a20a Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 2 Jul 2019 19:58:33 +0200 Subject: [PATCH] UI options. --- .../Controllers/UI/Models/UISettingsDto.cs | 16 +------- .../Areas/Api/Controllers/UI/MyUIOptions.cs | 6 +++ .../Areas/Api/Controllers/UI/UIController.cs | 7 +--- .../Frontend/Middlewares/IndexExtensions.cs | 27 +++++++++++++ .../Frontend/Middlewares/IndexMiddleware.cs | 15 +++----- .../Frontend/Middlewares/WebpackMiddleware.cs | 16 +------- src/Squidex/app/app.module.ts | 10 ++++- .../apps/pages/apps-page.component.ts | 6 ++- .../modals/onboarding-tooltip.component.ts | 1 + src/Squidex/app/framework/configurations.ts | 29 ++++++++++++++ .../services/onboarding.service.spec.ts | 28 +++++++++----- .../framework/services/onboarding.service.ts | 13 +++++-- .../geolocation-editor.component.ts | 38 +++++++------------ .../must-be-authenticated.guard.spec.ts | 28 ++++++++++++-- .../guards/must-be-authenticated.guard.ts | 13 ++++++- .../must-be-not-authenticated.guard.spec.ts | 30 ++++++++++++--- .../guards/must-be-not-authenticated.guard.ts | 13 +++++-- .../app/shared/services/ui.service.spec.ts | 2 +- src/Squidex/app/shared/services/ui.service.ts | 3 -- .../shared/services/workflows.service.spec.ts | 2 +- src/Squidex/appsettings.json | 31 ++++++++------- 21 files changed, 215 insertions(+), 119 deletions(-) diff --git a/src/Squidex/Areas/Api/Controllers/UI/Models/UISettingsDto.cs b/src/Squidex/Areas/Api/Controllers/UI/Models/UISettingsDto.cs index 675b1265d..2183a87e8 100644 --- a/src/Squidex/Areas/Api/Controllers/UI/Models/UISettingsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/UI/Models/UISettingsDto.cs @@ -3,26 +3,12 @@ // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.ComponentModel.DataAnnotations; +// ==========================================================================using System.ComponentModel.DataAnnotations; namespace Squidex.Areas.Api.Controllers.UI.Models { public sealed class UISettingsDto { - /// - /// The type of the map control. - /// - [Required] - public string MapType { get; set; } - - /// - /// The key for the map control. - /// - [Required] - public string MapKey { get; set; } - /// /// True when the user can create apps. /// diff --git a/src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs b/src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs index 206d380ef..ca8bdcc5e 100644 --- a/src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs +++ b/src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs @@ -15,6 +15,12 @@ namespace Squidex.Areas.Api.Controllers.UI public MapOptions Map { get; set; } + public bool HideNews { get; set; } + + public bool HideOnboarding { get; set; } + + public bool RedirectToLogin { get; set; } + public bool OnlyAdminsCanCreateApps { get; set; } public sealed class MapOptions diff --git a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs index 3ca2f79fb..dd12c5be5 100644 --- a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs +++ b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs @@ -48,14 +48,9 @@ namespace Squidex.Areas.Api.Controllers.UI { var result = new UISettingsDto { - MapType = uiOptions.Map?.Type ?? "OSM", - MapKey = uiOptions.Map?.GoogleMaps?.Key + CanCreateApps = !uiOptions.OnlyAdminsCanCreateApps || Context.Permissions.Includes(CreateAppPermission) }; - var canCreateApps = !uiOptions.OnlyAdminsCanCreateApps || Context.Permissions.Includes(CreateAppPermission); - - result.CanCreateApps = canCreateApps; - return Ok(result); } diff --git a/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs b/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs index 13db98ab4..518bb7ae9 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs @@ -7,6 +7,11 @@ using System; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Squidex.Areas.Api.Controllers.UI; +using Squidex.Infrastructure.Json; namespace Squidex.Areas.Frontend.Middlewares { @@ -26,5 +31,27 @@ namespace Squidex.Areas.Frontend.Middlewares { return context.Response.ContentType?.ToLower().Contains("text/html") == true; } + + public static string AdjustHtml(this string html, HttpContext httpContext) + { + var result = html; + + if (httpContext.Request.PathBase.HasValue) + { + result = result.Replace("", $""); + } + + var uiOptions = httpContext.RequestServices.GetService>()?.Value; + + if (uiOptions != null) + { + var jsonSerializer = httpContext.RequestServices.GetRequiredService(); + var jsonOptions = jsonSerializer.Serialize(uiOptions, false); + + result = result.Replace("", $""); + } + + return result; + } } } diff --git a/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs b/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs index 9925e0513..cf4a2dde8 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs @@ -25,7 +25,7 @@ namespace Squidex.Areas.Frontend.Middlewares { var basePath = context.Request.PathBase; - if (context.IsHtmlPath() && basePath.HasValue) + if (context.IsHtmlPath() && context.Response.StatusCode != 304) { var responseBuffer = new MemoryStream(); var responseBody = context.Response.Body; @@ -36,24 +36,19 @@ namespace Squidex.Areas.Frontend.Middlewares context.Response.Body = responseBody; - var response = Encoding.UTF8.GetString(responseBuffer.ToArray()); + var html = Encoding.UTF8.GetString(responseBuffer.ToArray()); - response = AdjustBase(response, basePath); + html = html.AdjustHtml(context); - context.Response.ContentLength = Encoding.UTF8.GetByteCount(response); + context.Response.ContentLength = Encoding.UTF8.GetByteCount(html); context.Response.Body = responseBody; - await context.Response.WriteAsync(response); + await context.Response.WriteAsync(html); } else { await next(context); } } - - private static string AdjustBase(string response, string baseUrl) - { - return response.Replace("", $""); - } } } diff --git a/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs b/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs index d71fb128d..8ed930af6 100644 --- a/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs +++ b/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs @@ -37,7 +37,7 @@ namespace Squidex.Areas.Frontend.Middlewares { var html = await result.Content.ReadAsStringAsync(); - html = AdjustBase(html, context.Request.PathBase); + html = html.AdjustHtml(context); await context.Response.WriteHtmlAsync(html); } @@ -58,7 +58,7 @@ namespace Squidex.Areas.Frontend.Middlewares var html = Encoding.UTF8.GetString(responseBuffer.ToArray()); - html = AdjustBase(html, context.Request.PathBase); + html = html.AdjustHtml(context); context.Response.ContentLength = Encoding.UTF8.GetByteCount(html); context.Response.Body = responseBody; @@ -71,17 +71,5 @@ namespace Squidex.Areas.Frontend.Middlewares await next(context); } } - - private static string AdjustBase(string html, PathString baseUrl) - { - if (baseUrl.HasValue) - { - return html.Replace("", $""); - } - else - { - return html; - } - } } } diff --git a/src/Squidex/app/app.module.ts b/src/Squidex/app/app.module.ts index 98b2a6c97..f4c512db3 100644 --- a/src/Squidex/app/app.module.ts +++ b/src/Squidex/app/app.module.ts @@ -23,7 +23,8 @@ import { DecimalSeparatorConfig, SqxFrameworkModule, SqxSharedModule, - TitlesConfig + TitlesConfig, + UIOptions } from './shared'; import { SqxShellModule } from './shell'; @@ -49,6 +50,10 @@ export function configApiUrl() { } } +export function configUIOptions() { + return new UIOptions(window['options']); +} + export function configTitles() { return new TitlesConfig({}, undefined, 'Squidex Headless CMS'); } @@ -88,7 +93,8 @@ export function configCurrency() { { provide: ApiUrlConfig, useFactory: configApiUrl }, { provide: CurrencyConfig, useFactory: configCurrency }, { provide: DecimalSeparatorConfig, useFactory: configDecimalSeparator }, - { provide: TitlesConfig, useFactory: configTitles } + { provide: TitlesConfig, useFactory: configTitles }, + { provide: UIOptions, useFactory: configUIOptions } ], entryComponents: [AppComponent] }) diff --git a/src/Squidex/app/features/apps/pages/apps-page.component.ts b/src/Squidex/app/features/apps/pages/apps-page.component.ts index 845d48924..f51a6a7d3 100644 --- a/src/Squidex/app/features/apps/pages/apps-page.component.ts +++ b/src/Squidex/app/features/apps/pages/apps-page.component.ts @@ -17,6 +17,7 @@ import { LocalStoreService, NewsService, OnboardingService, + UIOptions, UIState } from '@app/shared'; @@ -40,7 +41,8 @@ export class AppsPageComponent implements OnInit { public readonly uiState: UIState, private readonly localStore: LocalStoreService, private readonly newsService: NewsService, - private readonly onboardingService: OnboardingService + private readonly onboardingService: OnboardingService, + private readonly uiOptions: UIOptions ) { } @@ -52,7 +54,7 @@ export class AppsPageComponent implements OnInit { if (shouldShowOnboarding && apps.length === 0) { this.onboardingService.disable('dialog'); this.onboardingDialog.show(); - } else { + } else if (!this.uiOptions.get('hideNews')) { const newsVersion = this.localStore.getInt('squidex.news.version'); this.newsService.getFeatures(newsVersion) diff --git a/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts b/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts index 98fc8ee3f..cc1e55afa 100644 --- a/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts +++ b/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts @@ -45,6 +45,7 @@ export class OnboardingTooltipComponent extends StatefulComponent implements OnD private readonly renderer: Renderer2 ) { super(changeDetector, {}); + } public ngOnDestroy() { diff --git a/src/Squidex/app/framework/configurations.ts b/src/Squidex/app/framework/configurations.ts index 4bb75d0bf..18b3180d2 100644 --- a/src/Squidex/app/framework/configurations.ts +++ b/src/Squidex/app/framework/configurations.ts @@ -5,6 +5,35 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +export class UIOptions { + constructor( + private readonly value: any + ) { + } + + public get(path: string) { + if (!path) { + return undefined; + } + + let value = this.value; + + if (value) { + const parts = path.split('.'); + + for (let part of parts) { + value = value[part]; + + if (!value) { + break; + } + } + } + + return value; + } +} + export class ApiUrlConfig { public readonly value: string; diff --git a/src/Squidex/app/framework/services/onboarding.service.spec.ts b/src/Squidex/app/framework/services/onboarding.service.spec.ts index 0dc5042ae..715a189d7 100644 --- a/src/Squidex/app/framework/services/onboarding.service.spec.ts +++ b/src/Squidex/app/framework/services/onboarding.service.spec.ts @@ -7,6 +7,8 @@ import { OnboardingService, OnboardingServiceFactory } from './onboarding.service'; +import { UIOptions } from './../configurations'; + class LocalStoreMock { private store = {}; @@ -27,46 +29,52 @@ describe('OnboardingService', () => { }); it('should instantiate from factory', () => { - const onboardingService = OnboardingServiceFactory(localStore); + const onboardingService = OnboardingServiceFactory(new UIOptions({}), localStore); expect(onboardingService).toBeDefined(); }); it('should instantiate', () => { - const onboardingService = new OnboardingService(localStore); + const onboardingService = new OnboardingService(new UIOptions({}), localStore); expect(onboardingService).toBeDefined(); }); - it('should return true when value not in store', () => { + it('should show when value not in store', () => { localStore.set('squidex.onboarding.disable.feature-a1', '0'); - const onboardingService = new OnboardingService(localStore); + const onboardingService = new OnboardingService(new UIOptions({}), localStore); expect(onboardingService.shouldShow('feature-a2')).toBeTruthy(); }); - it('should return false when value in store', () => { + it('should not show when value in store', () => { localStore.set('squidex.onboarding.disable.feature-b1', '1'); - const onboardingService = new OnboardingService(localStore); + const onboardingService = new OnboardingService(new UIOptions({}), localStore); expect(onboardingService.shouldShow('feature-b1')).toBeFalsy(); }); - it('should return false when disabled', () => { - const onboardingService = new OnboardingService(localStore); + it('should not show when disabled', () => { + const onboardingService = new OnboardingService(new UIOptions({}), localStore); onboardingService.disable('feature-c1'); expect(onboardingService.shouldShow('feature-c1')).toBeFalsy(); }); - it('should return false when all disabled', () => { - const onboardingService = new OnboardingService(localStore); + it('should not show when all disabled', () => { + const onboardingService = new OnboardingService(new UIOptions({}), localStore); onboardingService.disableAll(); expect(onboardingService.shouldShow('feature-d1')).toBeFalsy(); }); + + it('should not show when disabled by setting', () => { + const onboardingService = new OnboardingService(new UIOptions({ hideOnboarding: true }), localStore); + + expect(onboardingService.shouldShow('feature-d1')).toBeFalsy(); + }); }); \ No newline at end of file diff --git a/src/Squidex/app/framework/services/onboarding.service.ts b/src/Squidex/app/framework/services/onboarding.service.ts index e2249d050..a8e48d3bb 100644 --- a/src/Squidex/app/framework/services/onboarding.service.ts +++ b/src/Squidex/app/framework/services/onboarding.service.ts @@ -12,15 +12,20 @@ import { Injectable } from '@angular/core'; import { LocalStoreService } from './local-store.service'; -export const OnboardingServiceFactory = (localStore: LocalStoreService) => { - return new OnboardingService(localStore); +import { UIOptions } from './../configurations'; + +export const OnboardingServiceFactory = (uiOptions: UIOptions, localStore: LocalStoreService) => { + return new OnboardingService(uiOptions, localStore); }; @Injectable() export class OnboardingService { - constructor( + private readonly disabled: boolean; + + constructor(uiOptions: UIOptions, private readonly localStore: LocalStoreService ) { + this.disabled = uiOptions.get('hideOnboardingTooltips'); } public disableAll() { @@ -32,7 +37,7 @@ export class OnboardingService { } public shouldShow(key: string) { - return this.shouldShowKey(key) && this.shouldShowKey('all'); + return !this.disabled && this.shouldShowKey(key) && this.shouldShowKey('all'); } private shouldShowKey(key: string) { diff --git a/src/Squidex/app/shared/components/geolocation-editor.component.ts b/src/Squidex/app/shared/components/geolocation-editor.component.ts index 6de6e97bf..b358ef4fb 100644 --- a/src/Squidex/app/shared/components/geolocation-editor.component.ts +++ b/src/Squidex/app/shared/components/geolocation-editor.component.ts @@ -12,7 +12,7 @@ import { ResourceLoaderService, StatefulControlComponent, Types, - UIState, + UIOptions, ValidatorsEx } from '@app/shared/internal'; @@ -28,10 +28,6 @@ interface Geolocation { longitude: number; } -interface State { - isGoogleMaps: boolean; -} - @Component({ selector: 'sqx-geolocation-editor', styleUrls: ['./geolocation-editor.component.scss'], @@ -39,7 +35,8 @@ interface State { providers: [SQX_GEOLOCATION_EDITOR_CONTROL_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush }) -export class GeolocationEditorComponent extends StatefulControlComponent implements AfterViewInit { +export class GeolocationEditorComponent extends StatefulControlComponent implements AfterViewInit { + private readonly isGoogleMaps: boolean; private marker: any; private map: any; private value: Geolocation | null = null; @@ -73,11 +70,11 @@ export class GeolocationEditorComponent extends StatefulControlComponent { - const isGoogleMaps = settings.mapType === 'GoogleMaps'; - - this.next(s => ({ ...s, isGoogleMaps })); - - if (!this.snapshot.isGoogleMaps) { - this.ngAfterViewInitOSM(); - } else { - this.ngAfterViewInitGoogle(settings.mapKey); - } - }); + if (!this.isGoogleMaps) { + this.ngAfterViewInitOSM(); + } else { + this.ngAfterViewInitGoogle(this.uiOptions.get('map.googleMaps.key')); + } } private ngAfterViewInitOSM() { @@ -224,11 +214,11 @@ export class GeolocationEditorComponent extends StatefulControlComponent { + this.map.addListener('bounds_changed', () => { searchBox.setBounds(this.map.getBounds()); }); - searchBox.addListener('places_changed', (event: any) => { + searchBox.addListener('places_changed', () => { let places = searchBox.getPlaces(); if (places.length === 1) { diff --git a/src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts b/src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts index 027ca52da..e439d95d2 100644 --- a/src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts +++ b/src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts @@ -9,24 +9,25 @@ import { Router } from '@angular/router'; import { of } from 'rxjs'; import { IMock, It, Mock, Times } from 'typemoq'; -import { AuthService } from '@app/shared'; +import { AuthService, UIOptions } from '@app/shared'; import { MustBeAuthenticatedGuard } from './must-be-authenticated.guard'; describe('MustBeAuthenticatedGuard', () => { let router: IMock; - let authService: IMock; - let authGuard: MustBeAuthenticatedGuard; + let uiOptions = new UIOptions({ map: { type: 'OSM' } }); + let uiOptionsRedirect = new UIOptions({ map: { type: 'OSM' }, redirectToLogin: true }); beforeEach(() => { router = Mock.ofType(); authService = Mock.ofType(); - authGuard = new MustBeAuthenticatedGuard(authService.object, router.object); }); it('should navigate to default page if not authenticated', () => { + const authGuard = new MustBeAuthenticatedGuard(uiOptions, authService.object, router.object); + authService.setup(x => x.userChanges) .returns(() => of(null)); @@ -42,6 +43,8 @@ describe('MustBeAuthenticatedGuard', () => { }); it('should return true if authenticated', () => { + const authGuard = new MustBeAuthenticatedGuard(uiOptions, authService.object, router.object); + authService.setup(x => x.userChanges) .returns(() => of({})); @@ -55,4 +58,21 @@ describe('MustBeAuthenticatedGuard', () => { router.verify(x => x.navigate(It.isAny()), Times.never()); }); + + it('should login redirect if redirect enabled', () => { + const authGuard = new MustBeAuthenticatedGuard(uiOptionsRedirect, authService.object, router.object); + + authService.setup(x => x.userChanges) + .returns(() => of(null)); + + let result: boolean; + + authGuard.canActivate().subscribe(x => { + result = x; + }); + + expect(result!).toBeFalsy(); + + authService.verify(x => x.loginRedirect(), Times.once()); + }); }); \ No newline at end of file diff --git a/src/Squidex/app/shared/guards/must-be-authenticated.guard.ts b/src/Squidex/app/shared/guards/must-be-authenticated.guard.ts index bdf76f49b..f851720f2 100644 --- a/src/Squidex/app/shared/guards/must-be-authenticated.guard.ts +++ b/src/Squidex/app/shared/guards/must-be-authenticated.guard.ts @@ -10,14 +10,19 @@ import { CanActivate, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { map, take, tap } from 'rxjs/operators'; +import { UIOptions } from '@app/framework'; + import { AuthService } from './../services/auth.service'; @Injectable() export class MustBeAuthenticatedGuard implements CanActivate { - constructor( + private readonly redirect: boolean; + + constructor(uiOptions: UIOptions, private readonly authService: AuthService, private readonly router: Router ) { + this.redirect = uiOptions.get('redirectToLogin'); } public canActivate(): Observable { @@ -25,7 +30,11 @@ export class MustBeAuthenticatedGuard implements CanActivate { take(1), tap(user => { if (!user) { - this.router.navigate(['']); + if (this.redirect) { + this.authService.loginRedirect(); + } else { + this.router.navigate(['']); + } } }), map(user => !!user)); diff --git a/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts b/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts index 2bf342413..5448e4071 100644 --- a/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts +++ b/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts @@ -9,24 +9,25 @@ import { Router } from '@angular/router'; import { of } from 'rxjs'; import { IMock, It, Mock, Times } from 'typemoq'; -import { AuthService } from '@app/shared'; +import { AuthService, UIOptions } from '@app/shared'; import { MustBeNotAuthenticatedGuard } from './must-be-not-authenticated.guard'; -describe('MustNotBeAuthenticatedGuard', () => { +describe('MustBeNotAuthenticatedGuard', () => { let router: IMock; - let authService: IMock; - let authGuard: MustBeNotAuthenticatedGuard; + let uiOptions = new UIOptions({ map: { type: 'OSM' } }); + let uiOptionsRedirect = new UIOptions({ map: { type: 'OSM' }, redirectToLogin: true }); beforeEach(() => { router = Mock.ofType(); authService = Mock.ofType(); - authGuard = new MustBeNotAuthenticatedGuard(authService.object, router.object); }); it('should navigate to app page if authenticated', () => { + const authGuard = new MustBeNotAuthenticatedGuard(uiOptions, authService.object, router.object); + authService.setup(x => x.userChanges) .returns(() => of({})); @@ -42,6 +43,8 @@ describe('MustNotBeAuthenticatedGuard', () => { }); it('should return true if not authenticated', () => { + const authGuard = new MustBeNotAuthenticatedGuard(uiOptions, authService.object, router.object); + authService.setup(x => x.userChanges) .returns(() => of(null)); @@ -55,4 +58,21 @@ describe('MustNotBeAuthenticatedGuard', () => { router.verify(x => x.navigate(It.isAny()), Times.never()); }); + + it('should login redirect and return false if redirect enabled', () => { + const authGuard = new MustBeNotAuthenticatedGuard(uiOptionsRedirect, authService.object, router.object); + + authService.setup(x => x.userChanges) + .returns(() => of(null)); + + let result: boolean; + + authGuard.canActivate().subscribe(x => { + result = x; + }); + + expect(result!).toBeFalsy(); + + authService.verify(x => x.loginRedirect(), Times.once()); + }); }); \ No newline at end of file diff --git a/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts b/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts index 67c4a346d..0e88a9e26 100644 --- a/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts +++ b/src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts @@ -10,24 +10,31 @@ import { CanActivate, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { map, take, tap } from 'rxjs/operators'; +import { UIOptions } from '@app/framework'; + import { AuthService } from './../services/auth.service'; @Injectable() export class MustBeNotAuthenticatedGuard implements CanActivate { - constructor( + private readonly redirect: boolean; + + constructor(uiOptions: UIOptions, private readonly authService: AuthService, private readonly router: Router ) { + this.redirect = uiOptions.get('redirectToLogin'); } public canActivate(): Observable { return this.authService.userChanges.pipe( take(1), tap(user => { - if (user) { + if (this.redirect) { + this.authService.loginRedirect(); + } else if (user) { this.router.navigate(['app']); } }), - map(user => !user)); + map(user => !user && !this.redirect)); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/ui.service.spec.ts b/src/Squidex/app/shared/services/ui.service.spec.ts index 537ea44e0..5a5f9236d 100644 --- a/src/Squidex/app/shared/services/ui.service.spec.ts +++ b/src/Squidex/app/shared/services/ui.service.spec.ts @@ -40,7 +40,7 @@ describe('UIService', () => { settings = result; }); - const response: UISettingsDto = { mapType: 'OSM', mapKey: '', canCreateApps: true }; + const response: UISettingsDto = { canCreateApps: true }; const req = httpMock.expectOne('http://service/p/api/ui/settings'); diff --git a/src/Squidex/app/shared/services/ui.service.ts b/src/Squidex/app/shared/services/ui.service.ts index cdadc29a1..285ace324 100644 --- a/src/Squidex/app/shared/services/ui.service.ts +++ b/src/Squidex/app/shared/services/ui.service.ts @@ -13,9 +13,6 @@ import { catchError } from 'rxjs/operators'; import { ApiUrlConfig } from '@app/framework'; export interface UISettingsDto { - readonly mapType: string; - readonly mapKey?: string; - readonly canCreateApps: boolean; } diff --git a/src/Squidex/app/shared/services/workflows.service.spec.ts b/src/Squidex/app/shared/services/workflows.service.spec.ts index cdf96ce7f..c42b620f0 100644 --- a/src/Squidex/app/shared/services/workflows.service.spec.ts +++ b/src/Squidex/app/shared/services/workflows.service.spec.ts @@ -147,7 +147,7 @@ describe('Workflow', () => { it('should create empty workflow', () => { const workflow = new WorkflowDto(); - expect(workflow.initial); + expect(workflow.initial).not.toBeDefined(); }); it('should add step to workflow', () => { diff --git a/src/Squidex/appsettings.json b/src/Squidex/appsettings.json index d8c5ba74f..399cee8f7 100644 --- a/src/Squidex/appsettings.json +++ b/src/Squidex/appsettings.json @@ -65,7 +65,12 @@ */ "key": "AIzaSyB_Z8l3nwUxZhMJykiDUJy6bSHXXlwcYMg" } - } + }, + + /* + * Redirect to login automatically. + */ + "redirectTopLogin": false }, "email": { @@ -73,29 +78,29 @@ /* * The host name to your email server. */ - "server": "", - /* + "server": "", + /* * The sender email address. */ - "sender": "hello@squidex.io", - /* + "sender": "hello@squidex.io", + /* * The username to authenticate to your email server. */ - "username": "", - /* + "username": "", + /* * The password to authenticate to your email server. */ - "password": "", - /* + "password": "", + /* * Always use SSL if possible. */ - "enableSsl": true, - /* + "enableSsl": true, + /* * The port to your email server. */ - "port": 465 - }, + "port": 465 + }, "notifications": { /* * The email subject when a new user is added as contributor.