From 3a03c8e1e872df4b69cda8097e2b20a474ae72c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Fri, 31 Jul 2026 20:55:45 +0300 Subject: [PATCH] =?UTF-8?q?Kullan=C4=B1c=C4=B1lara=20UserType=20s=C3=BCtun?= =?UTF-8?q?u=20eklendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Identity/Dto/UserInfoViewModel.cs | 2 + .../DynamicApi/CreateUpdateUserInput.cs | 2 + .../Identity/PlatformIdentityAppService.cs | 4 +- .../UserInfoViewModelMappingExtensions.cs | 1 + .../ListForms/ListFormDynamicApiAppService.cs | 3 + .../Seeds/LanguagesData.json | 24 +++ .../Seeds/ListFormSeeder_Administration.cs | 150 ++++++++++-------- .../Seeds/PlatformIdentityDataSeeder.cs | 1 + .../PlatformConsts.cs | 10 ++ .../Extensions/AbpIdentityUserExtensions.cs | 10 ++ .../PlatformEfCoreEntityExtensionMappings.cs | 10 ++ ....cs => 20260731143824_Initial.Designer.cs} | 7 +- ...3_Initial.cs => 20260731143824_Initial.cs} | 1 + .../PlatformDbContextModelSnapshot.cs | 5 + .../Seeds/TenantIdentityDataSeeder.cs | 1 + .../Identity/PlatformSignInManager.cs | 12 +- ui/src/proxy/admin/models.ts | 1 + ui/src/types/shared.ts | 5 + .../views/admin/user-management/Details.tsx | 66 ++++++-- ui/src/views/list/CardView.tsx | 104 ++++++++++-- 20 files changed, 321 insertions(+), 98 deletions(-) rename api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/{20260730174943_Initial.Designer.cs => 20260731143824_Initial.Designer.cs} (99%) rename api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/{20260730174943_Initial.cs => 20260731143824_Initial.cs} (99%) diff --git a/api/src/Sozsoft.Platform.Application.Contracts/Identity/Dto/UserInfoViewModel.cs b/api/src/Sozsoft.Platform.Application.Contracts/Identity/Dto/UserInfoViewModel.cs index 7ea947e8..0692c649 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/Identity/Dto/UserInfoViewModel.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/Identity/Dto/UserInfoViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Volo.Abp.ObjectExtending; +using static Sozsoft.Platform.PlatformConsts; namespace Sozsoft.Platform.Identity.Dto; @@ -20,6 +21,7 @@ public class UserInfoViewModel : ExtensibleObject public bool LockoutEnabled { get; set; } public DateTimeOffset? LockoutEnd { get; set; } public DateTime? LoginEndDate { get; set; } + public UserType UserType { get; set; } public bool IsVerified { get; set; } public List userRoleNames { get; set; } public AssignedRoleViewModel[] Roles { get; set; } diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateUpdateUserInput.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateUpdateUserInput.cs index a6aef1a4..2f812459 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateUpdateUserInput.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateUpdateUserInput.cs @@ -1,4 +1,5 @@ using System; +using static Sozsoft.Platform.PlatformConsts; namespace Sozsoft.Platform.ListForms.DynamicApi; @@ -17,5 +18,6 @@ public class CreateUpdateUserInput public bool? IsActive { get; set; } public bool? LockoutEnabled { get; set; } public string[] RoleNames { get; set; } + public UserType UserType { get; set; } } diff --git a/api/src/Sozsoft.Platform.Application/Identity/PlatformIdentityAppService.cs b/api/src/Sozsoft.Platform.Application/Identity/PlatformIdentityAppService.cs index 2261c4c3..c78c1cfe 100644 --- a/api/src/Sozsoft.Platform.Application/Identity/PlatformIdentityAppService.cs +++ b/api/src/Sozsoft.Platform.Application/Identity/PlatformIdentityAppService.cs @@ -8,6 +8,7 @@ using Sozsoft.Platform.Entities; using Sozsoft.Platform.Extensions; using Sozsoft.Platform.Identity.Dto; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using OpenIddict.Abstractions; @@ -287,8 +288,9 @@ public class PlatformIdentityAppService : ApplicationService user.SetGraduationSchool(UserInfo.GraduationSchool); user.SetBloodType(UserInfo.BloodType); user.SetAvatar(UserInfo.Avatar); + user.SetUserType(UserInfo.UserType); - await UserManager.UpdateAsync(user); + (await UserManager.UpdateAsync(user)).CheckErrors(); } [Authorize(IdentityPermissions.Users.Update)] diff --git a/api/src/Sozsoft.Platform.Application/Identity/UserInfoViewModelMappingExtensions.cs b/api/src/Sozsoft.Platform.Application/Identity/UserInfoViewModelMappingExtensions.cs index bfca22aa..c71e8943 100644 --- a/api/src/Sozsoft.Platform.Application/Identity/UserInfoViewModelMappingExtensions.cs +++ b/api/src/Sozsoft.Platform.Application/Identity/UserInfoViewModelMappingExtensions.cs @@ -11,6 +11,7 @@ public static class UserInfoViewModelMappingExtensions { public static UserInfoViewModel MapIdentityExtraProperties(this UserInfoViewModel userInfoViewModel, IdentityUser user) { + userInfoViewModel.UserType = user.GetUserType(); userInfoViewModel.IsVerified = user.GetIsVerified(); userInfoViewModel.LoginEndDate = user.GetLoginEndDate(); userInfoViewModel.Avatar = user.GetAvatar(); diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs index e26b7c95..1d17da81 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs @@ -127,6 +127,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic user.SetDepartmentId(ParseGuid(input.Data.DepartmentId)); user.SetJobPositionId(ParseGuid(input.Data.JobPositionId)); user.SetIsVerified(verify); + user.SetUserType(input.Data.UserType); await SaveAvatarAsync(user, input.Data.Avatar); @@ -199,6 +200,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic user.SetJobPositionId(ParseGuid(input.Data.JobPositionId)); } + user.SetUserType(input.Data.UserType); + await SaveAvatarAsync(user, input.Data.Avatar); (await userManager.UpdateAsync(user)).CheckErrors(); diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index ddc9bec0..e05e4094 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -2502,6 +2502,24 @@ "en": "Education Level", "tr": "Eğitim Seviyesi" }, + { + "resourceName": "Platform", + "key": "Abp.Account.UserType", + "en": "User Type", + "tr": "Kullanıcı Tipi" + }, + { + "resourceName": "Platform", + "key": "Abp.Account.UserType.Internal", + "en": "Internal", + "tr": "İç Kullanıcı" + }, + { + "resourceName": "Platform", + "key": "Abp.Account.UserType.External", + "en": "External", + "tr": "Dış Kullanıcı" + }, { "resourceName": "Platform", "key": "Abp.Account.Nationality", @@ -17454,6 +17472,12 @@ "en": "URL", "tr": "URL" }, + { + "resourceName": "Platform", + "key": "App.Listform.ListformField.UserType", + "en": "User Type", + "tr": "Kullanıcı Tipi" + }, { "resourceName": "Platform", "key": "App.Listform.ListformField.UserName", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index 1bb15e0f..d11002ba 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -891,6 +891,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep }, }), FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] { + new() { FieldName = "UserType", FieldDbType = DbType.Int32, Value = "0", CustomValueType = FieldCustomValueTypeEnum.Value }, new() { FieldName = "IsActive", FieldDbType = DbType.Boolean, Value = "true", CustomValueType = FieldCustomValueTypeEnum.Value } }), WidgetsJson = JsonSerializer.Serialize(new List @@ -946,8 +947,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep #region Users Fields await _listFormFieldRepository.InsertManyAsync( [ - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -964,8 +964,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -988,8 +987,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1012,8 +1010,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1036,8 +1033,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1060,8 +1056,41 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + + new ListFormField { + ListFormCode = listForm.ListFormCode, + RoleId = null, + UserId = null, + CultureName = LanguageCodes.En, + SourceDbType = DbType.Int16, + FieldName = "UserType", + EditGroupOrderNo = 1, + EditOrderNo = 5, + EditorType2 = EditorTypes.dxSelectBox, + ColSpan = 1, + CaptionName = "App.Listform.ListformField.UserType", + Width = 0, + ListOrderNo = 5, + Visible = true, + IsActive = true, + LookupJson = JsonSerializer.Serialize(new LookupDto + { + + DataSourceType = UiLookupDataSourceTypeEnum.StaticData, + DisplayExpr = "name", + ValueExpr = "key", + LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] { + new () { Key=PlatformConsts.AbpIdentity.User.InternalUserTypeDefaultValue, Name="Internal" }, + new () { Key=PlatformConsts.AbpIdentity.User.ExternalUserTypeDefaultValue, Name="External" }, + }), + }), + ValidationRuleJson = DefaultValidationRuleRequiredJson, + ColumnCustomizationJson = DefaultColumnCustomizationJson, + PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), + PivotSettingsJson = DefaultPivotSettingsJson + }, + + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1069,12 +1098,12 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep SourceDbType = DbType.String, FieldName = "PhoneNumber", EditGroupOrderNo = 1, - EditOrderNo = 5, + EditOrderNo = 6, EditorType2 = EditorTypes.dxTextBox, ColSpan = 1, CaptionName = "Abp.Identity.User.UserInformation.PhoneNumber", Width = 0, - ListOrderNo = 5, + ListOrderNo = 6, Visible = true, IsActive = true, @@ -1085,8 +1114,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1094,7 +1122,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep SourceDbType = DbType.String, FieldName = "WorkHour", EditGroupOrderNo = 1, - EditOrderNo = 6, + EditOrderNo = 7, EditorType2 = EditorTypes.dxSelectBox, ColSpan = 1, EditorOptions = EditorOptionValues.ShowClearButton, @@ -1112,8 +1140,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1121,7 +1148,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep SourceDbType = DbType.Guid, FieldName = "DepartmentId", EditGroupOrderNo = 1, - EditOrderNo = 7, + EditOrderNo = 8, EditorType2 = EditorTypes.dxSelectBox, ColSpan = 1, EditorOptions = EditorOptionValues.ShowClearButton, @@ -1145,8 +1172,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1154,7 +1180,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep SourceDbType = DbType.Guid, FieldName = "JobPositionId", EditGroupOrderNo = 1, - EditOrderNo = 8, + EditOrderNo = 9, EditorType2 = EditorTypes.dxSelectBox, ColSpan = 1, EditorOptions = EditorOptionValues.ShowClearButton, @@ -1180,8 +1206,29 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { + ListFormCode = listForm.ListFormCode, + RoleId = null, + UserId = null, + CultureName = LanguageCodes.En, + SourceDbType = DbType.String, + FieldName = "Password", + EditGroupOrderNo = 1, + EditOrderNo = 10, + EditorType2 = EditorTypes.dxTextBox, + ColSpan = 1, + CaptionName = "App.Listform.ListformField.Password", + Width = 0, + ListOrderNo = 10, + Visible = false, + IsActive = false, + + ColumnCustomizationJson = DefaultColumnCustomizationJson, + PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), + PivotSettingsJson = DefaultPivotSettingsJson + }, + + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, @@ -1189,29 +1236,11 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep SourceDbType = DbType.Boolean, FieldName = "IsActive", EditGroupOrderNo = 1, - EditOrderNo = 10, + EditOrderNo = 11, EditorType2 = EditorTypes.dxCheckBox, ColSpan = 1, CaptionName = "App.Listform.ListformField.IsActive", Width = 0, - ListOrderNo = 10, - Visible = true, - IsActive = true, - - ColumnCustomizationJson = DefaultColumnCustomizationJson, - PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), - PivotSettingsJson = DefaultPivotSettingsJson - }, - new ListFormField - { - ListFormCode = listForm.ListFormCode, - RoleId = null, - UserId = null, - CultureName = LanguageCodes.En, - SourceDbType = DbType.Boolean, - FieldName = "IsVerified", - CaptionName = "App.Listform.ListformField.IsVerified", - Width = 0, ListOrderNo = 11, Visible = true, IsActive = true, @@ -1220,15 +1249,14 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, CultureName = LanguageCodes.En, SourceDbType = DbType.Boolean, - FieldName = "EmailConfirmed", - CaptionName = "App.Listform.ListformField.EmailConfirmed", + FieldName = "IsVerified", + CaptionName = "App.Listform.ListformField.IsVerified", Width = 0, ListOrderNo = 12, Visible = true, @@ -1238,15 +1266,14 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, CultureName = LanguageCodes.En, SourceDbType = DbType.Boolean, - FieldName = "TwoFactorEnabled", - CaptionName = "App.Listform.ListformField.TwoFactorEnabled", + FieldName = "EmailConfirmed", + CaptionName = "App.Listform.ListformField.EmailConfirmed", Width = 0, ListOrderNo = 13, Visible = true, @@ -1256,29 +1283,24 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - new ListFormField - { + new ListFormField { ListFormCode = listForm.ListFormCode, RoleId = null, UserId = null, CultureName = LanguageCodes.En, - SourceDbType = DbType.String, - FieldName = "Password", - EditGroupOrderNo = 1, - EditOrderNo = 9, - EditorType2 = EditorTypes.dxTextBox, - ColSpan = 1, - CaptionName = "App.Listform.ListformField.Password", + SourceDbType = DbType.Boolean, + FieldName = "TwoFactorEnabled", + CaptionName = "App.Listform.ListformField.TwoFactorEnabled", Width = 0, ListOrderNo = 14, - Visible = false, - IsActive = false, + Visible = true, + IsActive = true, ColumnCustomizationJson = DefaultColumnCustomizationJson, PermissionJson = DefaultFieldPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, PlatformConsts.IdentityPermissions.Users.Default, PlatformConsts.IdentityPermissions.Users.Update, true, true, false), PivotSettingsJson = DefaultPivotSettingsJson }, - ]); + ]); #endregion } #endregion diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PlatformIdentityDataSeeder.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PlatformIdentityDataSeeder.cs index 85d490f5..bad9769b 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PlatformIdentityDataSeeder.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PlatformIdentityDataSeeder.cs @@ -155,6 +155,7 @@ public class PlatformIdentityDataSeeder : IdentityDataSeeder adminUser.SetDepartmentId(PlatformConsts.AbpIdentity.User.AdminDepartmentIdDefaultValue); adminUser.SetJobPositionId(PlatformConsts.AbpIdentity.User.AdminJobPositionIdDefaultValue); adminUser.SetAvatar(GetAvatar(tenantId?.ToString(), adminUser.Id.ToString())); + adminUser.SetUserType(PlatformConsts.AbpIdentity.User.InternalUserTypeDefaultValue); (await UserManager.CreateAsync(adminUser, adminPassword, validatePassword: false)).CheckErrors(); result.CreatedAdminUser = true; diff --git a/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs b/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs index 3c8f331f..2b7002cf 100644 --- a/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs +++ b/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs @@ -15,6 +15,12 @@ public static class PlatformConsts public const string React = "UI"; public const char MultiValueDelimiter = '|'; + public enum UserType + { + Internal, + External + } + public static class EditorOptionValues { public static string Disabled = "{ \"disabled\" : true }"; @@ -119,6 +125,7 @@ public static class PlatformConsts public const string Surname = "Surname"; public const string LoginEndDate = "LoginEndDate"; public const string RoleNames = "RoleNames"; + public const string UserType = "UserType"; public const string IsVerified = "IsVerified"; public const string Avatar = "Avatar"; public const string RocketUsername = "RocketUsername"; @@ -188,6 +195,9 @@ public static class PlatformConsts public static readonly DateTime AdminBirthDateDefaultValue = new(1981, 8, 27); public const string AdminBirthPlaceDefaultValue = "Kadıköy, İstanbul"; public const string AdminMaritalStatusDefaultValue = "Evli"; + + public const UserType InternalUserTypeDefaultValue = PlatformConsts.UserType.Internal; + public const UserType ExternalUserTypeDefaultValue = PlatformConsts.UserType.External; } public static class OrganizationUnits diff --git a/api/src/Sozsoft.Platform.Domain/Extensions/AbpIdentityUserExtensions.cs b/api/src/Sozsoft.Platform.Domain/Extensions/AbpIdentityUserExtensions.cs index 6e9326ca..73ce7e1c 100644 --- a/api/src/Sozsoft.Platform.Domain/Extensions/AbpIdentityUserExtensions.cs +++ b/api/src/Sozsoft.Platform.Domain/Extensions/AbpIdentityUserExtensions.cs @@ -11,6 +11,16 @@ public static class AbpIdentityUserExtensions return $"{user.Name} {user.Surname}".Trim(); } + //UserType + public static void SetUserType(this IdentityUser user, PlatformConsts.UserType userType) + { + user.SetProperty(PlatformConsts.AbpIdentity.User.UserType, userType); + } + public static PlatformConsts.UserType GetUserType(this IdentityUser user) + { + return user.GetProperty(PlatformConsts.AbpIdentity.User.UserType); + } + //IsVerified public static void SetIsVerified(this IdentityUser user, bool isVerified) { diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEfCoreEntityExtensionMappings.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEfCoreEntityExtensionMappings.cs index fd5c6cf6..17e027e8 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEfCoreEntityExtensionMappings.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEfCoreEntityExtensionMappings.cs @@ -5,6 +5,7 @@ using Volo.Abp.ObjectExtending; using Volo.Abp.PermissionManagement; using Volo.Abp.TenantManagement; using Volo.Abp.Threading; +using static Sozsoft.Platform.PlatformConsts; namespace Sozsoft.Platform.EntityFrameworkCore; @@ -19,6 +20,15 @@ public static class PlatformEfCoreEntityExtensionMappings OneTimeRunner.Run(() => { + ObjectExtensionManager.Instance + .MapEfCoreProperty( + PlatformConsts.AbpIdentity.User.UserType, + (entityBuilder, propertyBuilder) => + { + propertyBuilder.IsRequired().HasDefaultValue(PlatformConsts.AbpIdentity.User.InternalUserTypeDefaultValue); + } + ); + ObjectExtensionManager.Instance .MapEfCoreProperty( PlatformConsts.AbpIdentity.User.IsVerified, diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.Designer.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.Designer.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.Designer.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.Designer.cs index d40e3059..719b591f 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.Designer.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Sozsoft.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20260730174943_Initial")] + [Migration("20260731143824_Initial")] partial class Initial { /// @@ -7801,6 +7801,11 @@ namespace Sozsoft.Platform.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("UserName"); + b.Property("UserType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + b.Property("Village") .HasMaxLength(128) .HasColumnType("nvarchar(128)"); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.cs index d25e75f5..9b3d0366 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260730174943_Initial.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260731143824_Initial.cs @@ -462,6 +462,7 @@ namespace Sozsoft.Platform.Migrations SerialNo = table.Column(type: "nvarchar(32)", maxLength: 32, nullable: true), SskNo = table.Column(type: "nvarchar(32)", maxLength: 32, nullable: true), TerminationDate = table.Column(type: "datetime2", nullable: true), + UserType = table.Column(type: "int", nullable: false, defaultValue: 0), Village = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), VolumeNo = table.Column(type: "nvarchar(32)", maxLength: 32, nullable: true), WorkHour = table.Column(type: "nvarchar(max)", nullable: true), diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index f9a10b2a..e6394ef8 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -7798,6 +7798,11 @@ namespace Sozsoft.Platform.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("UserName"); + b.Property("UserType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + b.Property("Village") .HasMaxLength(128) .HasColumnType("nvarchar(128)"); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantIdentityDataSeeder.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantIdentityDataSeeder.cs index 9664b63e..c6fd6d71 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantIdentityDataSeeder.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantIdentityDataSeeder.cs @@ -153,6 +153,7 @@ public class TenantIdentityDataSeeder : IdentityDataSeeder adminUser.SetDepartmentId(PlatformConsts.AbpIdentity.User.AdminDepartmentIdDefaultValue); adminUser.SetJobPositionId(PlatformConsts.AbpIdentity.User.AdminJobPositionIdDefaultValue); adminUser.SetAvatar(GetAvatar(tenantId?.ToString(), adminUser.Id.ToString())); + adminUser.SetUserType(PlatformConsts.AbpIdentity.User.InternalUserTypeDefaultValue); (await UserManager.CreateAsync(adminUser, adminPassword, validatePassword: false)).CheckErrors(); result.CreatedAdminUser = true; diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/Identity/PlatformSignInManager.cs b/api/src/Sozsoft.Platform.HttpApi.Host/Identity/PlatformSignInManager.cs index 22cae521..dc865bdb 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/Identity/PlatformSignInManager.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/Identity/PlatformSignInManager.cs @@ -308,13 +308,19 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager using var uow = unitOfWorkManager.Begin(requiresNew: true, isTransactional: false); var sessions = await identitySessionRepository.GetListAsync(); - // Bu kullanıcı hariç diğer distinct aktif kullanıcı sayısını hesapla. // Kullanıcının kendi oturumu varsa (refresh) o kişi tekrar sayılmaz. - var otherActiveUserCount = sessions + var activeUserIds = sessions .Where(s => s.UserId != user.Id) .Select(s => s.UserId) .Distinct() - .Count(); + .ToList(); + + // Aktif session kullanıcılarını IdentityUserManager üzerinden topluca yükle + // ve yalnızca UserType = 0 (Internal) olanları concurrent limite dahil et. + var otherActiveUserCount = (await userManager.Users + .Where(u => activeUserIds.Contains(u.Id)) + .ToListAsync()) + .Count(u => u.GetUserType() == PlatformConsts.UserType.Internal); if (otherActiveUserCount >= maxConcurrentUsers) { diff --git a/ui/src/proxy/admin/models.ts b/ui/src/proxy/admin/models.ts index 58c2415e..d23c093c 100644 --- a/ui/src/proxy/admin/models.ts +++ b/ui/src/proxy/admin/models.ts @@ -122,6 +122,7 @@ export interface UserInfoViewModel extends ExtensibleObject { lockoutEnabled: boolean lockoutEnd?: string loginEndDate?: Date | string + userType: number isVerified: boolean userRoleNames: string[] roles: AssignedRoleViewModel[] diff --git a/ui/src/types/shared.ts b/ui/src/types/shared.ts index 856dcc1d..0089d8d4 100644 --- a/ui/src/types/shared.ts +++ b/ui/src/types/shared.ts @@ -8,3 +8,8 @@ export type SelectBoxOptionWithGroup = { label?: string group?: string } + +export type SelectBoxOptionByNumber = { + value?: number + label?: string +} \ No newline at end of file diff --git a/ui/src/views/admin/user-management/Details.tsx b/ui/src/views/admin/user-management/Details.tsx index 7da0c6e0..c99e1e0f 100644 --- a/ui/src/views/admin/user-management/Details.tsx +++ b/ui/src/views/admin/user-management/Details.tsx @@ -76,7 +76,11 @@ import { import 'react-advanced-cropper/dist/style.css' import { useParams } from 'react-router-dom' import * as Yup from 'yup' -import { SelectBoxOption, SelectBoxOptionWithGroup } from '@/types/shared' +import { + SelectBoxOption, + SelectBoxOptionWithGroup, + SelectBoxOptionByNumber, +} from '@/types/shared' import { AdaptableCard, ConfirmDialog } from '@/components/shared' import { AssignedClaimViewModel, UserInfoViewModel } from '@/proxy/admin/models' import { APP_NAME, AVATAR_URL } from '@/constants/app.constant' @@ -254,7 +258,7 @@ function UserDetails() { -
+
- - } - /> + + + {({ field, form }: FieldProps) => { + const userTypes: SelectBoxOptionByNumber[] = [ + { + value: 0, + label: translate('::Abp.Account.UserType.Internal'), + }, + { + value: 1, + label: translate('::Abp.Account.UserType.External'), + }, + ] + return ( + -
+
-
+
+
+ + } + /> + +
+
-
+
-
+
-
+
diff --git a/ui/src/views/list/CardView.tsx b/ui/src/views/list/CardView.tsx index 5fb65b2e..d717a782 100644 --- a/ui/src/views/list/CardView.tsx +++ b/ui/src/views/list/CardView.tsx @@ -6,11 +6,12 @@ import { APP_NAME, DX_CLASSNAMES } from '@/constants/app.constant' import { ColumnFormatDto, DbTypeEnum, + FieldCustomValueTypeEnum, GridDto, PlatformEditorTypes, SubFormTabTypeEnum, } from '@/proxy/form/models' -import { getList } from '@/services/form.service' +import { getList, getNextSequenceValue } from '@/services/form.service' import { useLocalization } from '@/utils/hooks/useLocalization' import { usePermission } from '@/utils/hooks/usePermission' import { useStoreActions, useStoreState } from '@/store' @@ -32,6 +33,7 @@ import DxCardView, { ToolbarItem, } from 'devextreme-react/card-view' import CustomStore from 'devextreme/data/custom_store' +import type { DataType } from 'devextreme/common' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createRoot } from 'react-dom/client' import { Helmet } from 'react-helmet' @@ -42,6 +44,7 @@ import { GridExtraFilterToolbar } from './GridExtraFilterToolbar' import { ImageUploadEditorComponent } from './editors/ImageUploadEditorComponent' import { ImageViewerEditorComponent } from './editors/ImageViewerEditorComponent' import { + autoNumber, extractSearchParamsFields, getEditingFormGroups, GridExtraFilterState, @@ -417,7 +420,9 @@ const CardView = (props: CardViewProps) => { const [isPopupFullScreen, setIsPopupFullScreen] = useState(false) const [formData, setFormData] = useState>() const formDataRef = useRef>() - formDataRef.current = formData + useEffect(() => { + formDataRef.current = formData + }, [formData]) const lookupDisplayValuesRef = useRef>>({}) const [lookupReadyState, setLookupReadyState] = useState({ listFormCode, ready: false }) const [notePanelTarget, setNotePanelTarget] = useState<{ @@ -689,7 +694,6 @@ const CardView = (props: CardViewProps) => { nextData[childField] = null }) formDataRef.current = nextData - setFormData(nextData) }, [cascadeChildrenByParent], ) @@ -859,7 +863,7 @@ const CardView = (props: CardViewProps) => { ...editorOptions, dataSource: typeof lookup.dataSource === 'function' - ? lookup.dataSource({ data: formData ?? {} }) + ? lookup.dataSource({ data: formDataRef.current ?? {} }) : lookup.dataSource, displayExpr: lookup.displayExpr, valueExpr: lookup.valueExpr, @@ -892,7 +896,7 @@ const CardView = (props: CardViewProps) => { : undefined, } }, - [formData, gridDto, imageUploadFormTemplate, imageViewerFormTemplate, mode, translate], + [gridDto, imageUploadFormTemplate, imageViewerFormTemplate, mode, translate], ) const editingFormItems = useMemo(() => { @@ -1009,6 +1013,86 @@ const CardView = (props: CardViewProps) => { const editingOptions = gridDto?.gridOptions.editingOptionDto const selectionOptions = gridDto?.gridOptions.selectionDto + const onInitNewCard = useCallback( + (event: CardViewTypes.InitNewCardEvent>) => { + const nextFormData = event.data as Record + formDataRef.current = nextFormData + + setMode('new') + setIsPopupFullScreen(useMobileEditPopup || (editingOptions?.popup?.fullScreen ?? false)) + + event.promise = (async () => { + const rawFilter = searchParamsRef.current?.get('filter') + let filters: any[] = [] + + if (rawFilter) { + try { + filters = extractSearchParamsFields(JSON.parse(rawFilter)) + } catch (error) { + console.error('Filter parse edilemedi:', error) + } + } + + for (const column of gridDto?.columnFormats ?? []) { + const fieldName = column.fieldName + if (!fieldName || extraFilters.some((filter) => filter.fieldName === fieldName)) { + continue + } + + if (column.defaultValue !== null && column.defaultValue !== undefined) { + if (typeof column.defaultValue === 'string' && column.defaultValue === '@AUTONUMBER') { + nextFormData[fieldName] = autoNumber() + } else if (column.defaultValueType === FieldCustomValueTypeEnum.Sequence) { + try { + const response = await getNextSequenceValue(String(column.defaultValue)) + nextFormData[fieldName] = response.data + } catch (error) { + console.error('Sequence default value alınamadı:', { + fieldName, + defaultValue: column.defaultValue, + error, + }) + } + } else { + nextFormData[fieldName] = column.defaultValue + } + } + + const fieldMatch = filters.find(([field]) => field === fieldName) + if (!fieldMatch) continue + + const value = fieldMatch[2] + switch (column.dataType as DataType) { + case 'date': + case 'datetime': + nextFormData[fieldName] = new Date(value) + break + case 'number': + nextFormData[fieldName] = Number(value) + break + case 'boolean': + nextFormData[fieldName] = value === true || value === 'true' + break + case 'object': + try { + nextFormData[fieldName] = JSON.parse(value) + } catch { + nextFormData[fieldName] = value + } + break + default: + nextFormData[fieldName] = value + break + } + } + + formDataRef.current = nextFormData + setFormData({ ...nextFormData }) + })() + }, + [editingOptions?.popup?.fullScreen, extraFilters, gridDto, useMobileEditPopup], + ) + const onSelectionChanged = useCallback( (event: CardViewTypes.SelectionChangedEvent) => { const selectedCardsData = event.selectedCardsData as Record[] @@ -1074,15 +1158,7 @@ const CardView = (props: CardViewProps) => { wordWrapEnabled={gridDto.gridOptions.rowDto?.whiteSpace !== 'nowrap'} onContentReady={onContentReady} onSelectionChanged={onSelectionChanged} - onInitNewCard={(event) => { - const nextFormData = (event.data as Record) ?? {} - formDataRef.current = nextFormData - setFormData(nextFormData) - setMode('new') - setIsPopupFullScreen( - useMobileEditPopup || (editingOptions?.popup?.fullScreen ?? false), - ) - }} + onInitNewCard={onInitNewCard} onEditingStart={(event) => { const nextFormData = (event.data as Record) ?? {} formDataRef.current = nextFormData