diff --git a/Directory.Packages.props b/Directory.Packages.props index 094d116f89..1cb2ae0b88 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -131,8 +131,8 @@ - - + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs index 109746e34f..b62d3f27ba 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs @@ -30,7 +30,7 @@ public class AbpAspNetCoreMvcUiThemeSharedModule : AbpModule { options.FileSets.AddEmbedded("Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared"); }); - + Configure(options => { options diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs index 27f3760000..5d8c15ba40 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs @@ -49,7 +49,8 @@ public class SharedThemeGlobalScriptContributor : BundleContributor "/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/toastr/abp-toastr.js", - "/libs/abp/aspnetcore-mvc-ui-theme-shared/date-range-picker/date-range-picker-extensions.js" + "/libs/abp/aspnetcore-mvc-ui-theme-shared/date-range-picker/date-range-picker-extensions.js", + "/libs/abp/aspnetcore-mvc-ui-theme-shared/authentication-state/authentication-state-listener.js" }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/authentication-state/authentication-state-listener.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/authentication-state/authentication-state-listener.js new file mode 100644 index 0000000000..848760f854 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/authentication-state/authentication-state-listener.js @@ -0,0 +1,30 @@ +(function () { + + const stateKey = 'authentication-state-id'; + + window.addEventListener('load', function () { + if (!abp || !abp.currentUser) { + return; + } + + if (!abp.currentUser.isAuthenticated) { + localStorage.removeItem(stateKey); + } else { + localStorage.setItem(stateKey, abp.currentUser.id); + } + + window.addEventListener('storage', function (event) { + + if (event.key !== stateKey || event.oldValue === event.newValue) { + return; + } + + if (event.oldValue || !event.newValue) { + window.location.reload(); + } else { + location.assign('/') + } + }); + }); + +}()); \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/Authentication/AbpAuthenticationHubFilter.cs b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/Authentication/AbpAuthenticationHubFilter.cs index ab79521159..baac1b538f 100644 --- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/Authentication/AbpAuthenticationHubFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/Authentication/AbpAuthenticationHubFilter.cs @@ -1,7 +1,9 @@ using System; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Volo.Abp.Security.Claims; namespace Volo.Abp.AspNetCore.SignalR.Authentication; @@ -11,7 +13,7 @@ public class AbpAuthenticationHubFilter : IHubFilter public virtual async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { var currentPrincipalAccessor = invocationContext.ServiceProvider.GetRequiredService(); - using (currentPrincipalAccessor.Change(invocationContext.Context.User!)) + using (currentPrincipalAccessor.Change((await GetDynamicClaimsPrincipalAsync(invocationContext.Context.User, invocationContext.ServiceProvider))!)) { return await next(invocationContext); } @@ -20,7 +22,7 @@ public class AbpAuthenticationHubFilter : IHubFilter public virtual async Task OnConnectedAsync(HubLifetimeContext context, Func next) { var currentPrincipalAccessor = context.ServiceProvider.GetRequiredService(); - using (currentPrincipalAccessor.Change(context.Context.User!)) + using (currentPrincipalAccessor.Change((await GetDynamicClaimsPrincipalAsync(context.Context.User, context.ServiceProvider))!)) { await next(context); } @@ -29,9 +31,27 @@ public class AbpAuthenticationHubFilter : IHubFilter public virtual async Task OnDisconnectedAsync(HubLifetimeContext context, Exception? exception, Func next) { var currentPrincipalAccessor = context.ServiceProvider.GetRequiredService(); - using (currentPrincipalAccessor.Change(context.Context.User!)) + using (currentPrincipalAccessor.Change((await GetDynamicClaimsPrincipalAsync(context.Context.User, context.ServiceProvider))!)) { await next(context, exception); } } + + protected virtual async Task GetDynamicClaimsPrincipalAsync(ClaimsPrincipal? claimsPrincipal, IServiceProvider serviceProvider) + { + if (claimsPrincipal == null) + { + return claimsPrincipal; + } + + if (claimsPrincipal.Identity != null && + claimsPrincipal.Identity.IsAuthenticated && + serviceProvider.GetRequiredService>().Value.IsDynamicClaimsEnabled) + { + var abpClaimsPrincipalFactory = serviceProvider.GetRequiredService(); + claimsPrincipal = await abpClaimsPrincipalFactory.CreateDynamicAsync(claimsPrincipal); + } + + return claimsPrincipal; + } } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJobArgs.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJobArgs.cs index 86a34b4210..0b30a9bfd1 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJobArgs.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJobArgs.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; using Volo.Abp.Data; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Emailing; [Serializable] -public class BackgroundEmailSendingJobArgs +public class BackgroundEmailSendingJobArgs : IMultiTenant { + public Guid? TenantId { get; set; } + public string? From { get; set; } public string To { get; set; } = default!; diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs index 986ad1c38a..dacbb195ab 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.BackgroundJobs; +using Volo.Abp.MultiTenancy; using Volo.Abp.Validation; namespace Volo.Abp.Emailing; @@ -18,6 +19,8 @@ public abstract class EmailSenderBase : IEmailSender { public ILogger Logger { get; set; } + protected ICurrentTenant CurrentTenant { get; } + protected IEmailSenderConfiguration Configuration { get; } protected IBackgroundJobManager BackgroundJobManager { get; } @@ -25,10 +28,14 @@ public abstract class EmailSenderBase : IEmailSender /// /// Constructor. /// - protected EmailSenderBase(IEmailSenderConfiguration configuration, IBackgroundJobManager backgroundJobManager) + protected EmailSenderBase( + ICurrentTenant currentTenant, + IEmailSenderConfiguration configuration, + IBackgroundJobManager backgroundJobManager) { Logger = NullLogger.Instance; + CurrentTenant = currentTenant; Configuration = configuration; BackgroundJobManager = backgroundJobManager; } @@ -96,6 +103,7 @@ public abstract class EmailSenderBase : IEmailSender await BackgroundJobManager.EnqueueAsync( new BackgroundEmailSendingJobArgs { + TenantId = CurrentTenant.Id, To = to, Subject = subject, Body = body, @@ -118,6 +126,7 @@ public abstract class EmailSenderBase : IEmailSender await BackgroundJobManager.EnqueueAsync( new BackgroundEmailSendingJobArgs { + TenantId = CurrentTenant.Id, From = from, To = to, Subject = subject, diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/NullEmailSender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/NullEmailSender.cs index 48fa8004ef..f73783ebeb 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/NullEmailSender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/NullEmailSender.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.BackgroundJobs; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Emailing; @@ -15,8 +16,8 @@ public class NullEmailSender : EmailSenderBase /// /// Creates a new object. /// - public NullEmailSender(IEmailSenderConfiguration configuration, IBackgroundJobManager backgroundJobManager) - : base(configuration, backgroundJobManager) + public NullEmailSender(ICurrentTenant currentTenant, IEmailSenderConfiguration configuration, IBackgroundJobManager backgroundJobManager) + : base(currentTenant, configuration, backgroundJobManager) { } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs index 62550c41f7..babb9f9d9a 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Emailing.Smtp; @@ -19,9 +20,10 @@ public class SmtpEmailSender : EmailSenderBase, ISmtpEmailSender, ITransientDepe /// Creates a new . /// public SmtpEmailSender( + ICurrentTenant currentTenant, ISmtpEmailSenderConfiguration smtpConfiguration, IBackgroundJobManager backgroundJobManager) - : base(smtpConfiguration, backgroundJobManager) + : base(currentTenant, smtpConfiguration, backgroundJobManager) { SmtpConfiguration = smtpConfiguration; } diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs index 96e436760e..c4fbd1be5e 100644 --- a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using MimeKit; using MimeKit.Utils; +using Volo.Abp.MultiTenancy; using SmtpClient = MailKit.Net.Smtp.SmtpClient; namespace Volo.Abp.MailKit; @@ -20,10 +21,12 @@ public class MailKitSmtpEmailSender : EmailSenderBase, IMailKitSmtpEmailSender protected ISmtpEmailSenderConfiguration SmtpConfiguration { get; } - public MailKitSmtpEmailSender(ISmtpEmailSenderConfiguration smtpConfiguration, + public MailKitSmtpEmailSender( + ICurrentTenant currentTenant, + ISmtpEmailSenderConfiguration smtpConfiguration, IBackgroundJobManager backgroundJobManager, IOptions abpMailKitConfiguration) - : base(smtpConfiguration, backgroundJobManager) + : base(currentTenant, smtpConfiguration, backgroundJobManager) { AbpMailKitOptions = abpMailKitConfiguration.Value; SmtpConfiguration = smtpConfiguration; diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs index 18c84b2e0b..adc2edf31b 100644 --- a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using NSubstitute; using Volo.Abp.BackgroundJobs; using Volo.Abp.Emailing.Smtp; +using Volo.Abp.MultiTenancy; using Volo.Abp.Testing; using Xunit; @@ -35,6 +36,7 @@ public class MailKitSmtpEmailSender_Tests : AbpIntegratedTest(); var mailConfig = Substitute.For(); var bgJob = Substitute.For(); @@ -44,7 +46,7 @@ public class MailKitSmtpEmailSender_Tests : AbpIntegratedTest; registerLocaleFn: (locale: string) => Promise; skipGetAppConfiguration?: boolean; + skipInitAuthService?: boolean; sendNullsAsQueryParam?: boolean; tenantKey?: string; localizations?: Localization[]; diff --git a/npm/ng-packs/packages/core/src/lib/models/index.ts b/npm/ng-packs/packages/core/src/lib/models/index.ts index c343ee2440..0156b77bda 100644 --- a/npm/ng-packs/packages/core/src/lib/models/index.ts +++ b/npm/ng-packs/packages/core/src/lib/models/index.ts @@ -8,3 +8,4 @@ export * from './session'; export * from './utility'; export * from './auth'; export * from './auth-events'; +export * from './sort'; diff --git a/npm/ng-packs/packages/core/src/lib/models/sort.ts b/npm/ng-packs/packages/core/src/lib/models/sort.ts new file mode 100644 index 0000000000..eb51d18d22 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/models/sort.ts @@ -0,0 +1,5 @@ +export interface SortableItem { + id?: string | number; + name?: string; + order?: number; +} diff --git a/npm/ng-packs/packages/core/src/lib/tokens/compare-func.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/compare-func.token.ts index bf66ec2b54..2c5185ce23 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/compare-func.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/compare-func.token.ts @@ -1,27 +1,33 @@ import { InjectionToken, inject } from '@angular/core'; +import { SortableItem } from '../models'; import { LocalizationService } from '../services'; -export const SORT_COMPARE_FUNC = new InjectionToken< 0 | 1 | -1 >('SORT_COMPARE_FUNC'); +export const SORT_COMPARE_FUNC = new InjectionToken<(a: SortableItem, b: SortableItem) => number>( + 'SORT_COMPARE_FUNC', +); export function compareFuncFactory() { - const localizationService = inject(LocalizationService) - const fn = (a,b) => { + const localizationService = inject(LocalizationService); + const fn = (a: SortableItem, b: SortableItem) => { const aName = localizationService.instant(a.name); const bName = localizationService.instant(b.name); const aNumber = a.order; const bNumber = b.order; - + if (!Number.isInteger(aNumber)) return 1; if (!Number.isInteger(bNumber)) return -1; - - if (aNumber > bNumber) return 1 - if (aNumber < bNumber) return -1 - - if ( aName > bName ) return 1; - if ( aName < bName ) return -1; - - return 0 - } - - return fn -} \ No newline at end of file + + if (aNumber > bNumber) return 1; + if (aNumber < bNumber) return -1; + + if (aName > bName) return 1; + if (aName < bName) return -1; + + if (a.id > b.id) return 1; + if (a.id < b.id) return -1; + + return 0; + }; + + return fn; +} diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index 782af0899d..4173bd96c6 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -29,7 +29,7 @@ export function getInitialData(injector: Injector) { const checkAuthenticationState = injector.get(CHECK_AUTHENTICATION_STATE_FN_KEY, noop, { optional: true, }); - if (authService) { + if (!options.skipInitAuthService && authService) { await authService.init(); } if (options.skipGetAppConfiguration) return; diff --git a/npm/ng-packs/packages/core/testing/src/lib/core-testing.module.ts b/npm/ng-packs/packages/core/testing/src/lib/core-testing.module.ts index e3ad0ade05..8f077fa628 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/core-testing.module.ts +++ b/npm/ng-packs/packages/core/testing/src/lib/core-testing.module.ts @@ -8,6 +8,9 @@ import { PermissionService, RestService, INCUDE_LOCALIZATION_RESOURCES_TOKEN, + OTHERS_GROUP, + compareFuncFactory, + SORT_COMPARE_FUNC, } from '@abp/ng.core'; import { APP_BASE_HREF } from '@angular/common'; import { ModuleWithProviders, NgModule } from '@angular/core'; @@ -66,6 +69,14 @@ export class CoreTestingModule { provide: INCUDE_LOCALIZATION_RESOURCES_TOKEN, useValue: false, }, + { + provide: OTHERS_GROUP, + useValue: 'AbpUi::OthersGroup', + }, + { + provide: SORT_COMPARE_FUNC, + useFactory: compareFuncFactory, + }, provideRoutes(routes), ], }; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts index e1048f907e..4c3137b332 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts @@ -1,10 +1,13 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { NavItem } from '../models/nav-item'; -import { Type } from '@angular/core'; +import { inject, Type } from '@angular/core'; +import { SORT_COMPARE_FUNC } from '@abp/ng.core'; export abstract class AbstractMenuService { protected abstract baseClass: Type; + protected readonly sortFn = inject(SORT_COMPARE_FUNC); + protected _items$ = new BehaviorSubject([]); get items(): T[] { @@ -52,10 +55,7 @@ export abstract class AbstractMenuService { this._items$.next(items); } - private sortItems(a: T, b: T) { - if (!a.order) return 1; - if (!b.order) return -1; - - return a.order - b.order; - } + sortItems = (a: T, b: T) => { + return this.sortFn(a, b); + }; }