diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js b/framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js index 51ff0151b6..52bec9bb7b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js @@ -245,4 +245,11 @@ var abp = abp || {}; } } } + + abp.clock = abp.clock || {}; + + abp.clock.setBrowserTimeZoneToCookie = function () { + abp.utils.setCookieValue('__timezone', Intl.DateTimeFormat().resolvedOptions().timeZone, new Date(new Date().setFullYear(new Date().getFullYear() + 1)), '/'); + } + })(); diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index cb69ea3120..e1256eb53e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -26,6 +26,8 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio protected IJSRuntime JSRuntime { get; } + protected IClock Clock { get; } + public WebAssemblyCachedApplicationConfigurationClient( AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy, ApplicationConfigurationCache cache, @@ -33,7 +35,8 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio ICurrentTimezoneProvider currentTimezoneProvider, AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy, ApplicationConfigurationChangedService applicationConfigurationChangedService, - IJSRuntime jsRuntime) + IJSRuntime jsRuntime, + IClock clock) { ApplicationConfigurationClientProxy = applicationConfigurationClientProxy; Cache = cache; @@ -42,6 +45,7 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio ApplicationLocalizationClientProxy = applicationLocalizationClientProxy; ApplicationConfigurationChangedService = applicationConfigurationChangedService; JSRuntime = jsRuntime; + Clock = clock; } public virtual async Task InitializeAsync() @@ -76,6 +80,11 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio ); CurrentTimezoneProvider.TimeZone = configurationDto.Timing.TimeZone.Iana.TimeZoneName; + + if (Clock.SupportsMultipleTimezone && !configurationDto.CurrentUser.IsAuthenticated) + { + await JSRuntime.InvokeVoidAsync("abp.clock.setBrowserTimeZoneToCookie"); + } } public virtual Task GetAsync() diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs index 2b8a00ec6c..4bcfdf347b 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs @@ -7,6 +7,7 @@ using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Settings; using Volo.Abp.Timing; +using Volo.Abp.Users; namespace Microsoft.AspNetCore.Timing; @@ -14,7 +15,18 @@ public class AbpTimeZoneMiddleware : AbpMiddlewareBase, ITransientDependency { public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { - var timezone = await GetTimezoneFromRequestAsync(context); + if (!context.RequestServices.GetRequiredService().SupportsMultipleTimezone) + { + await next(context); + return; + } + + string? timezone = null; + + if (!context.RequestServices.GetRequiredService().IsAuthenticated) + { + timezone = await GetTimezoneFromRequestAsync(context); + } if (timezone.IsNullOrWhiteSpace()) { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs index fd2f107ccd..f3da8fb77c 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs @@ -3,9 +3,13 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.AspNetCore.Mvc.Authorization; +using Volo.Abp.Security.Claims; using Volo.Abp.Timing; using Xunit; @@ -14,10 +18,20 @@ namespace Volo.Abp.AspNetCore.Mvc.Timing; public class AbpTimeZoneMiddleware_Tests : AspNetCoreMvcTestBase { private readonly ICurrentTimezoneProvider _currentTimezoneProvider; + private readonly FakeUserClaims _fakeRequiredService; public AbpTimeZoneMiddleware_Tests() { _currentTimezoneProvider = GetRequiredService(); + _fakeRequiredService = GetRequiredService(); + } + + protected override void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.Kind = DateTimeKind.Utc; + }); } [Fact] @@ -61,4 +75,51 @@ public class AbpTimeZoneMiddleware_Tests : AspNetCoreMvcTestBase result.ShouldBe("Europe/Istanbul"); } } + + [Fact] + public async Task Should_Not_Override_TimeZone_Setting_By_Request_For_Authenticated_User() + { + _fakeRequiredService.Claims.AddRange(new[] + { + new Claim(AbpClaimTypes.UserId, AuthTestController.FakeUserId.ToString()) + }); + + using (_currentTimezoneProvider.Change("Europe/Berlin")) + { + var result = await Client.GetStringAsync("api/timing-test"); + result.ShouldBe("UTC"); + } + + // Query string + using (_currentTimezoneProvider.Change("Europe/Berlin")) + { + var result = await Client.GetStringAsync("api/timing-test?__timezone=Europe/Istanbul"); + result.ShouldBe("UTC"); + } + + // Header + using (_currentTimezoneProvider.Change("Europe/Berlin")) + { + Client.DefaultRequestHeaders.Add("__timezone", "Asia/Shanghai"); + var result = await Client.GetStringAsync("api/timing-test"); + result.ShouldBe("UTC"); + } + + // Form + using (_currentTimezoneProvider.Change("Europe/Berlin")) + { + Client.DefaultRequestHeaders.Remove("__timezone"); + var result = await Client.PostAsync("api/timing-test", new FormUrlEncodedContent(new[] {new KeyValuePair("__timezone", "Europe/Germany")})); + (await result.Content.ReadAsStringAsync()).ShouldBe("UTC"); + } + + // Cookie + using (_currentTimezoneProvider.Change("Europe/Berlin")) + { + Client.DefaultRequestHeaders.Remove("__timezone"); + Client.DefaultRequestHeaders.Add("Cookie", "__timezone=Europe/Istanbul"); + var result = await Client.GetStringAsync("api/timing-test"); + result.ShouldBe("UTC"); + } + } } diff --git a/npm/packs/core/src/abp.js b/npm/packs/core/src/abp.js index 6ad09542fc..ac050351e1 100644 --- a/npm/packs/core/src/abp.js +++ b/npm/packs/core/src/abp.js @@ -823,6 +823,24 @@ var abp = abp || {}; return date.toLocaleString(culture, options); } + abp.clock.browserTimeZone = function () { + return Intl.DateTimeFormat().resolvedOptions().timeZone; + } + + abp.clock.trySetBrowserTimeZoneToCookie = true; + + abp.clock.setBrowserTimeZoneToCookie = function () { + if (!abp.clock.trySetBrowserTimeZoneToCookie || !abp.clock.supportsMultipleTimezone() || abp.currentUser.isAuthenticated) { + return; + } + + abp.utils.setCookieValue('__timezone', abp.clock.browserTimeZone(), new Date(new Date().setFullYear(new Date().getFullYear() + 1)), '/'); + } + + abp.event.on('abp.configurationInitialized', function () { + abp.clock.setBrowserTimeZoneToCookie(); + }); + /* FEATURES *************************************************/ abp.features = abp.features || {}; diff --git a/npm/packs/luxon/src/abp.luxon.js b/npm/packs/luxon/src/abp.luxon.js index 5e42183884..40b3f965b8 100644 --- a/npm/packs/luxon/src/abp.luxon.js +++ b/npm/packs/luxon/src/abp.luxon.js @@ -95,4 +95,8 @@ var abp = abp || {}; .setLocale(abp.localization.currentCulture.cultureName) .toLocaleString(options); } + + abp.clock.browserTimeZone = function () { + return luxon.DateTime.local().zoneName; + } })(jQuery);