SetMaxConcurrentUsers yapısı değiştirildi.
This commit is contained in:
parent
4fd22fe682
commit
4ae697600b
12 changed files with 30 additions and 73 deletions
|
|
@ -28,6 +28,5 @@ public class CreateUpdateTenantInput
|
|||
public string Email { get; set; }
|
||||
public string Website { get; set; }
|
||||
public string MenuGroup { get; set; }
|
||||
public int MaxConcurrentUsers { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,6 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
entity.SetEmail(input.Data.Email);
|
||||
entity.SetWebsite(input.Data.Website);
|
||||
entity.SetMenuGroup(input.Data.MenuGroup);
|
||||
entity.SetMaxConcurrentUsers(input.Data.MaxConcurrentUsers);
|
||||
|
||||
await tenantRepository.UpdateAsync(entity, autoSave: true);
|
||||
}
|
||||
|
|
@ -290,7 +289,6 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
entity.SetEmail(input.Data.Email);
|
||||
entity.SetWebsite(input.Data.Website);
|
||||
entity.SetMenuGroup(input.Data.MenuGroup);
|
||||
entity.SetMaxConcurrentUsers(input.Data.MaxConcurrentUsers);
|
||||
|
||||
await tenantRepository.UpdateAsync(entity, autoSave: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15132,12 +15132,6 @@
|
|||
"en": "Format Template",
|
||||
"tr": "Format Şablonu"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listform.ListformField.MaxConcurrentUsers",
|
||||
"en": "Max Concurrent Users",
|
||||
"tr": "Maksimum Eşzamanlı Kullanıcı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listform.ListformField.IsVerified",
|
||||
|
|
|
|||
|
|
@ -115,10 +115,9 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
|||
new EditingFormItemDto { Order=5, DataField = "PostalCode", ColSpan=1, EditorType2=EditorTypes.dxTextBox, EditorOptions=EditorOptionValues.ShowClearButton },
|
||||
new EditingFormItemDto { Order=6, DataField = "Email", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||
new EditingFormItemDto { Order=7, DataField = "Website", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||
new EditingFormItemDto { Order=8, DataField = "MaxConcurrentUsers", ColSpan=1, EditorType2=EditorTypes.dxNumberBox },
|
||||
new EditingFormItemDto { Order=9, DataField = "IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox },
|
||||
new EditingFormItemDto { Order=10, DataField = "Address1", ColSpan=3, EditorType2=EditorTypes.dxTextArea },
|
||||
new EditingFormItemDto { Order=11, DataField = "Address2", ColSpan=3, EditorType2=EditorTypes.dxTextArea },
|
||||
new EditingFormItemDto { Order=8, DataField = "IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox },
|
||||
new EditingFormItemDto { Order=9, DataField = "Address1", ColSpan=3, EditorType2=EditorTypes.dxTextArea },
|
||||
new EditingFormItemDto { Order=10, DataField = "Address2", ColSpan=3, EditorType2=EditorTypes.dxTextArea },
|
||||
]
|
||||
}
|
||||
}),
|
||||
|
|
@ -140,8 +139,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
|||
}),
|
||||
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
|
||||
new() { FieldName = "IsActive", FieldDbType = DbType.Boolean, Value = "true", CustomValueType = FieldCustomValueTypeEnum.Value },
|
||||
new() { FieldName = "Country", FieldDbType = DbType.String, Value = "Türkiye", CustomValueType = FieldCustomValueTypeEnum.Value },
|
||||
new() { FieldName = "MaxConcurrentUsers", FieldDbType = DbType.Int32, Value = "0", CustomValueType = FieldCustomValueTypeEnum.Value }
|
||||
new() { FieldName = "Country", FieldDbType = DbType.String, Value = "Türkiye", CustomValueType = FieldCustomValueTypeEnum.Value }
|
||||
}),
|
||||
SubFormsJson = JsonSerializer.Serialize(new List<dynamic>() {
|
||||
new {
|
||||
|
|
@ -542,21 +540,6 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
|||
PermissionJson = DefaultFieldPermissionJson(TenantManagementPermissions.Tenants.Create, TenantManagementPermissions.Tenants.Default, TenantManagementPermissions.Tenants.Update, true, true, false),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new ListFormField
|
||||
{
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.Int32,
|
||||
FieldName = "MaxConcurrentUsers",
|
||||
CaptionName = "App.Listform.ListformField.MaxConcurrentUsers",
|
||||
Width = 0,
|
||||
ListOrderNo = 21,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(TenantManagementPermissions.Tenants.Create, TenantManagementPermissions.Tenants.Default, TenantManagementPermissions.Tenants.Update, true, true, false),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
], autoSave: true);
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ public static class PlatformConsts
|
|||
public const string Email = "Email";
|
||||
public const string Website = "Website";
|
||||
public const string MenuGroup = "MenuGroup";
|
||||
public const string MaxConcurrentUsers = "MaxConcurrentUsers";
|
||||
}
|
||||
|
||||
public static class Branches
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ public static class PlatformModuleExtensionConfigurator
|
|||
tenantConfig.ConfigureTenant(entity =>
|
||||
{
|
||||
entity.AddOrUpdateProperty<bool>("IsActive");
|
||||
entity.AddOrUpdateProperty<int?>("MaxConcurrentUsers");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -165,14 +165,5 @@ public static class AbpTenantExtensions
|
|||
{
|
||||
return tenant.GetProperty<string>(PlatformConsts.Tenants.MenuGroup);
|
||||
}
|
||||
|
||||
public static void SetMaxConcurrentUsers(this Tenant tenant, int? maxConcurrentUsers)
|
||||
{
|
||||
tenant.SetProperty(PlatformConsts.Tenants.MaxConcurrentUsers, maxConcurrentUsers.HasValue ? (object)maxConcurrentUsers.Value : null);
|
||||
}
|
||||
public static int? GetMaxConcurrentUsers(this Tenant tenant)
|
||||
{
|
||||
return tenant.GetProperty<int?>(PlatformConsts.Tenants.MaxConcurrentUsers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -460,15 +460,6 @@ public static class PlatformEfCoreEntityExtensionMappings
|
|||
}
|
||||
);
|
||||
|
||||
ObjectExtensionManager.Instance
|
||||
.MapEfCoreProperty<Tenant, int?>(
|
||||
PlatformConsts.Tenants.MaxConcurrentUsers,
|
||||
(entityBuilder, propertyBuilder) =>
|
||||
{
|
||||
propertyBuilder.HasDefaultValue(0);
|
||||
}
|
||||
);
|
||||
|
||||
ObjectExtensionManager.Instance
|
||||
.MapEfCoreProperty<PermissionDefinitionRecord, string>(
|
||||
PlatformConsts.Permissions.MenuGroup,
|
||||
|
|
|
|||
|
|
@ -8430,11 +8430,6 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<int?>("MaxConcurrentUsers")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("MenuGroup")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ namespace Sozsoft.Platform.Migrations
|
|||
FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||
Founder = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
MaxConcurrentUsers = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
|
||||
MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||
MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||
OrganizationName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||
|
|
|
|||
|
|
@ -8427,11 +8427,6 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<int?>("MaxConcurrentUsers")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("MenuGroup")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Sozsoft.Platform.Extensions;
|
|||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
|
|
@ -31,6 +32,7 @@ public interface IPlatformSignInManager
|
|||
|
||||
public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||
{
|
||||
private const string UserLicenseProductName = "Public.products.userLicense";
|
||||
private readonly IClock clock;
|
||||
private readonly IRepository<IpRestriction, Guid> repositoryIp;
|
||||
private readonly IRepository<WorkHour, Guid> repositoryWorkHour;
|
||||
|
|
@ -39,6 +41,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
private readonly IIdentitySessionRepository identitySessionRepository;
|
||||
private readonly ICurrentTenant currentTenant;
|
||||
private readonly IUnitOfWorkManager unitOfWorkManager;
|
||||
private readonly IRepository<Order, Guid> orderRepository;
|
||||
|
||||
public PlatformSignInManager(
|
||||
IdentityUserManager userManager,
|
||||
|
|
@ -56,7 +59,8 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
ITenantRepository tenantRepository,
|
||||
IIdentitySessionRepository identitySessionRepository,
|
||||
ICurrentTenant currentTenant,
|
||||
IUnitOfWorkManager unitOfWorkManager
|
||||
IUnitOfWorkManager unitOfWorkManager,
|
||||
IRepository<Order, Guid> orderRepository
|
||||
) : base(
|
||||
userManager,
|
||||
contextAccessor,
|
||||
|
|
@ -76,6 +80,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
this.identitySessionRepository = identitySessionRepository;
|
||||
this.currentTenant = currentTenant;
|
||||
this.unitOfWorkManager = unitOfWorkManager;
|
||||
this.orderRepository = orderRepository;
|
||||
}
|
||||
|
||||
public async Task<bool> PreSignInCheckAsync(IdentityUser user)
|
||||
|
|
@ -273,7 +278,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tenant'a tanımlı MaxConcurrentUsers limitini aşmamak için login'i engeller.
|
||||
/// Tenant'a ait aktif Order'lardaki kullanıcı lisansı limitini aşmamak için login'i engeller.
|
||||
/// AbpSessions tablosundaki aktif oturumları sayar (farklı UserId'lere göre distinct).
|
||||
/// Kullanıcının kendisinin zaten oturumu varsa (refresh senaryosu) yeni concurrent user sayılmaz.
|
||||
/// </summary>
|
||||
|
|
@ -284,14 +289,8 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
return true;
|
||||
}
|
||||
|
||||
var tenant = await tenantRepository.FindAsync(user.TenantId.Value);
|
||||
if (tenant == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var maxConcurrentUsers = tenant.GetMaxConcurrentUsers();
|
||||
if (!maxConcurrentUsers.HasValue || maxConcurrentUsers.Value == 0)
|
||||
var maxConcurrentUsers = await GetActiveUserLicenseQuantityAsync(user.TenantId.Value);
|
||||
if (maxConcurrentUsers == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -311,11 +310,11 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
.Distinct()
|
||||
.Count();
|
||||
|
||||
if (otherActiveUserCount >= maxConcurrentUsers.Value)
|
||||
if (otherActiveUserCount >= maxConcurrentUsers)
|
||||
{
|
||||
Logger.LogWarning(PlatformEventIds.UserCannotSignInConcurrentUserLimit,
|
||||
"Tenant {TenantId} concurrent user limit of {Limit} reached. Active users: {ActiveCount}.",
|
||||
user.TenantId, maxConcurrentUsers.Value, otherActiveUserCount);
|
||||
user.TenantId, maxConcurrentUsers, otherActiveUserCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -325,5 +324,20 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
|||
return true;
|
||||
}
|
||||
|
||||
private async Task<int> GetActiveUserLicenseQuantityAsync(Guid tenantId)
|
||||
{
|
||||
using (currentTenant.Change(null))
|
||||
{
|
||||
var orderQuery = await orderRepository.WithDetailsAsync(order => order.Items);
|
||||
var activeOrders = await orderQuery
|
||||
.Where(order => order.TenantId == tenantId && order.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
return activeOrders
|
||||
.SelectMany(order => order.Items)
|
||||
.Where(item => item.ProductName == UserLicenseProductName)
|
||||
.Sum(item => item.Quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue