diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs index 474e5cbd57..c335c3c338 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs @@ -7,5 +7,9 @@ namespace Volo.Abp.Identity [Required] [StringLength(IdentityRoleConsts.MaxNameLength)] public string Name { get; set; } + + public bool IsDefault { get; set; } + + public bool IsPublic { get; set; } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs index 13aa96f41b..c25ceace56 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs @@ -6,5 +6,11 @@ namespace Volo.Abp.Identity public class IdentityRoleDto : EntityDto { public string Name { get; set; } + + public bool IsDefault { get; set; } + + public bool IsStatic { get; set; } + + public bool IsPublic { get; set; } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs index b8cbcb67a9..f3ad2f880a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs @@ -71,6 +71,9 @@ namespace Volo.Abp.Identity { var role = new IdentityRole(GuidGenerator.Create(), input.Name, CurrentTenant.Id); + role.IsDefault = input.IsDefault; + role.IsPublic = input.IsPublic; + (await _roleManager.CreateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); @@ -84,6 +87,9 @@ namespace Volo.Abp.Identity (await _roleManager.SetRoleNameAsync(role, input.Name)).CheckErrors(); + role.IsDefault = input.IsDefault; + role.IsPublic = input.IsPublic; + (await _roleManager.UpdateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs index 02e0f320ac..1aa90b8b5f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs @@ -63,6 +63,10 @@ namespace Volo.Abp.Identity if (adminRole == null) { adminRole = new IdentityRole(_guidGenerator.Create(), adminRoleName, tenantId); + + adminRole.IsStatic = true; + adminRole.IsPublic = true; + CheckIdentityErrors(await _roleManager.CreateAsync(adminRole)); if (adminRolePermissions != null) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs index 8c5edd173f..8d87bf8788 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs @@ -39,6 +39,21 @@ namespace Volo.Abp.Identity [DisableAuditing] public virtual string ConcurrencyStamp { get; set; } + /// + /// A default role is automatically assigned to a new user + /// + public virtual bool IsDefault { get; set; } + + /// + /// A static role can not be deleted/renamed + /// + public virtual bool IsStatic { get; set; } + + /// + /// A user can see other user's public roles + /// + public virtual bool IsPublic { get; set; } + /// /// Initializes a new instance of . /// diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs index e59a056566..c66d501146 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Services; +using Volo.Abp.Identity.Localization; using Volo.Abp.Threading; namespace Volo.Abp.Identity @@ -14,6 +17,7 @@ namespace Volo.Abp.Identity { protected override CancellationToken CancellationToken => _cancellationTokenProvider.Token; + private readonly IStringLocalizer _localizer; private readonly ICancellationTokenProvider _cancellationTokenProvider; public IdentityRoleManager( @@ -21,7 +25,8 @@ namespace Volo.Abp.Identity IEnumerable> roleValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, - ILogger logger, + ILogger logger, + IStringLocalizer localizer, ICancellationTokenProvider cancellationTokenProvider) : base( store, @@ -30,6 +35,7 @@ namespace Volo.Abp.Identity errors, logger) { + _localizer = localizer; _cancellationTokenProvider = cancellationTokenProvider; } @@ -43,5 +49,25 @@ namespace Volo.Abp.Identity return role; } + + public override async Task SetRoleNameAsync(IdentityRole role, string name) + { + if (role.IsStatic && role.Name != name) + { + throw new BusinessException(_localizer["Identity.StaticRoleRenamingErrorMessage"]); // TODO: localize & change exception type + } + + return await base.SetRoleNameAsync(role,name); + } + + public override async Task DeleteAsync(IdentityRole role) + { + if (role.IsStatic) + { + throw new BusinessException(_localizer["Identity.StaticRoleDeletionErrorMessage"]); // TODO: localize & change exception type + } + + return await base.DeleteAsync(role); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json index c906f523b1..6ecf7122c6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json @@ -26,6 +26,8 @@ "Identity.UserLockoutNotEnabled": "Lockout is not enabled for this user.", "Identity.UserNameNotFound": "User {0} does not exist.", "Identity.UserNotInRole": "User is not in role '{0}'.", - "Identity.PasswordConfirmationFailed": "Password does not match the confirm password." + "Identity.PasswordConfirmationFailed": "Password does not match the confirm password.", + "Identity.StaticRoleRenamingErrorMessage": "Static roles can not be renamed.", + "Identity.StaticRoleDeletionErrorMessage": "Static roles can not be deleted." } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index dff0faef2b..af5cfd19e8 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -97,6 +97,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore b.Property(r => r.Name).IsRequired().HasMaxLength(IdentityRoleConsts.MaxNameLength); b.Property(r => r.NormalizedName).IsRequired().HasMaxLength(IdentityRoleConsts.MaxNormalizedNameLength); + b.Property(r => r.IsDefault).HasColumnName(nameof(IdentityRole.IsDefault)); + b.Property(r => r.IsStatic).HasColumnName(nameof(IdentityRole.IsStatic)); + b.Property(r => r.IsPublic).HasColumnName(nameof(IdentityRole.IsPublic)); b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired(); diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json index a7370325e4..e16e24134b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json @@ -8,6 +8,9 @@ "EmailAddress": "Email address", "PhoneNumber": "Phone number", "UserInformations": "User informations", + "DisplayName:IsDefault": "Default", + "DisplayName:IsStatic": "Static", + "DisplayName:IsPublic": "Public", "Roles": "Roles", "Password": "Password", "PersonalInfo": "Personal Info", diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json index b6806008b8..5393b25f43 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json +++ b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json @@ -6,6 +6,9 @@ "NewUser": "Yeni kullanıcı", "UserName": "Kullanıcı adı", "EmailAddress": "E-posta adresi", + "DisplayName:IsDefault": "Varsayılan", + "DisplayName:IsStatic": "Sabit", + "DisplayName:IsPublic": "Herkese Açık", "PhoneNumber": "Telefon numarası", "UserInformations": "Kullanıcı bilgileri", "Roles": "Roller", @@ -31,6 +34,8 @@ "DisplayName:NewPassword": "Yeni şifre", "DisplayName:NewPasswordConfirm": "Yeni şifre (tekrar)", "PasswordChangedMessage": "Şifreniz başarıyla değiştirildi.", - "PersonalSettingsSavedMessage": "Kişisel bilgileriniz başarıyla kaydedildi." + "PersonalSettingsSavedMessage": "Kişisel bilgileriniz başarıyla kaydedildi.", + "Identity.StaticRoleRenamingErrorMessage": "Bir Sabit rolün ismi değiştirilemez.", + "Identity.StaticRoleDeletionErrorMessage": "Bir Sabit rol silinemez." } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml index 833aa979c7..ce075d0b58 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml @@ -7,12 +7,14 @@ @{ Layout = null; } - +
- + + + - +
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs index bf91f4c5c6..7477439821 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs @@ -33,6 +33,12 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Roles [StringLength(IdentityRoleConsts.MaxNameLength)] [Display(Name = "DisplayName:RoleName")] public string Name { get; set; } + + [Display(Name = "DisplayName:IsDefault")] + public bool IsDefault { get; set; } + + [Display(Name = "DisplayName:IsPublic")] + public bool IsPublic { get; set; } } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml index 4f20d63091..b09cfe2dcb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml @@ -7,12 +7,22 @@ @{ Layout = null; } - +
- + + @if (Model.Role.IsStatic) + { + + } + else + { + + } + + - \ No newline at end of file +
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs index 22a13c6795..58703c211e 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs @@ -44,6 +44,14 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Roles [StringLength(IdentityRoleConsts.MaxNameLength)] [Display(Name = "DisplayName:RoleName")] public string Name { get; set; } + + [Display(Name = "DisplayName:IsDefault")] + public bool IsDefault { get; set; } + + public bool IsStatic { get; set; } + + [Display(Name = "DisplayName:IsPublic")] + public bool IsPublic { get; set; } } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js index b450fa069c..ee013ff1e9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js @@ -45,8 +45,8 @@ }, { text: l('Delete'), - visible: function () { - return true; //TODO: Check permission + visible: function (data) { + return !data.isStatic; //TODO: Check permission }, confirmMessage: function (data) { return l('RoleDeletionConfirmationMessage', data.record.name)}, action: function (data) { diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs index 21432e941d..ce7a5a0507 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs @@ -28,9 +28,14 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users { UserInfo = new UserInfoViewModel(); - Roles = ObjectMapper.Map, AssignedRoleViewModel[]>( - await _identityRoleAppService.GetAllListAsync() - ); + var roleDtoList = await _identityRoleAppService.GetAllListAsync(); + + Roles = ObjectMapper.Map, AssignedRoleViewModel[]>(roleDtoList); + + foreach (var role in Roles) + { + role.IsAssigned = role.IsDefault; + } } public async Task OnPostAsync() @@ -82,6 +87,8 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users public string Name { get; set; } public bool IsAssigned { get; set; } + + public bool IsDefault { get; set; } } } }