Open Closed

customize edit user page #4017


User avatar
0
hussein created
  • ABP Framework version: v6.0.1
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no
  • Exception message and stack trace:
  • Steps to reproduce the issue:"

1- I want to customize the user UI, to add a new tab page when editing the user

2- how to prevent a user who has the privilege to manage the users from deleting the Admin user or Sys Role?


5 Answer(s)
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    You can override the existing cshtml file of the modal via following this documentation: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface#overriding-a-razor-page-cshtml

    To achieve that, create a file in this path:

    • /Pages/Identity/Users/CreateModal.cshtml

    • And content of this newly created file should be:

    @page
    @using Microsoft.AspNetCore.Mvc.Localization
    @using Microsoft.Extensions.Localization
    @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
    @using Volo.Abp.Data
    @using Volo.Abp.Identity
    @using Volo.Abp.Identity.Localization
    @using Volo.Abp.Identity.Settings
    @using Volo.Abp.Identity.Web.Pages.Identity.Users
    @using Volo.Abp.Localization
    @using Volo.Abp.ObjectExtending
    @using Volo.Abp.Settings
    @model Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel
    @inject ISettingProvider SettingProvider
    @inject IHtmlLocalizer<IdentityResource> L
    @inject IStringLocalizerFactory StringLocalizerFactory
    @{
        Layout = null;
    }
    <form method="post" asp-page="/Identity/Users/CreateModal">
        <abp-modal>
            <abp-modal-header title="@L["NewUser"].Value"></abp-modal-header>
            <abp-modal-body>
                <abp-tabs name="create-user-modal-tabs">
                    <abp-tab title="@L["UserInformations"].Value">
                        <abp-input asp-for="UserInfo.UserName" />
                        <abp-input asp-for="UserInfo.Name" />
                        <abp-input asp-for="UserInfo.Surname" />
                        <div class="mb-3">
                            <label asp-for="UserInfo.Password" class="form-label">@L["Password"] *</label>
                            <div class="input-group">
                                <input type="password" class="form-control" maxlength="@IdentityUserConsts.MaxPasswordLength" asp-for="UserInfo.Password" />
                                <button class="btn btn-secondary" type="button" id="PasswordVisibilityButton"><i class="fa fa-eye-slash" aria-hidden="true"></i></button>
                            </div>
                            <span asp-validation-for="UserInfo.Password"></span>
                        </div>
                        <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                        @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<CreateModalModel.UserInfoViewModel>())
                        {
                            if (!propertyInfo.Name.EndsWith("_Text"))
                            {
                                if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                                {
                                    if (propertyInfo.Type.IsEnum)
                                    {
                                        Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                    }
                                    <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                                label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                                autocomplete-api-url="@propertyInfo.Lookup.Url"
                                                autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                                autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                                autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                                autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                                autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                                autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                                }
                                else
                                {
                                    <abp-input type="@propertyInfo.GetInputType()"
                                               asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                               label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                               asp-format="@propertyInfo.GetInputFormatOrNull()"
                                               value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                                }
                            }
                        }
                        <abp-input asp-for="UserInfo.PhoneNumber" />
                        <abp-input asp-for="UserInfo.IsActive" />
                        <abp-input asp-for="UserInfo.LockoutEnabled" />
                        @if (await SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail))
                        {
                            <abp-input asp-for="UserInfo.SendConfirmationEmail" />
                        }
                    </abp-tab>
                    <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                        @for (var i = 0; i < Model.Roles.Length; i++)
                        {
                            var role = Model.Roles[i];
                            if (role.IsDefault)
                            {
    
                                <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" checked="checked" />
                            }
                            else
                            {
                                <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" />
                            }
    
                            <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                        }
                    </abp-tab>
                    @if (Model.OrganizationUnits.Any())
                    {
                        <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">
                            <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                                <ul class="jstree-container-ul jstree-children" role="group">
                                    @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                    {
                                        @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                        {
                                            Depth = 0,
                                            Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                            OrganizationUnits = Model.OrganizationUnits
                                        })
                                    }
                                </ul>
                            </div>
                            @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                            {
                                var organizationUnits = Model.OrganizationUnits[i];
                                <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                                <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                                <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                            }
                        </abp-tab>
                    }
                    
                    <abp-tab name="your-custom-tab" title="Your Custom Tab">
                        YOUR TAB CONTENT HERE 👈
                    </abp-tab>
                </abp-tabs>
            </abp-modal-body>
            <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
        </abp-modal>
    </form>
    <input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />
    
  • User Avatar
    0
    hussein created

    thanks enisn appreciated , could you share with me the EditModal and the code behind the file for the razor page what about my second question plz?

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Yeah sure,

    You can use following files to override:

    • /Pages/Identity/Users/EditModal.cshtml
    @page
    @using Microsoft.AspNetCore.Mvc.Localization
    @using Microsoft.Extensions.Localization
    @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
    @using Volo.Abp.Data
    @using Volo.Abp.Identity.Localization
    @using Volo.Abp.Identity.Web.Pages.Identity.Users
    @using Volo.Abp.Localization
    @using Volo.Abp.ObjectExtending
    @model EditModalModel
    @inject IHtmlLocalizer<IdentityResource> L
    @inject IStringLocalizerFactory StringLocalizerFactory
    @{
        Layout = null;
    }
    <form method="post" asp-page="/Identity/Users/EditModal">
        <abp-modal>
            <abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
            <abp-modal-body>
                <abp-tabs name="create-user-modal-tabs">
                    <abp-tab title="@L["UserInformation"].Value">
                        <input asp-for="UserInfo.Id" />
                        <input asp-for="UserInfo.ConcurrencyStamp" />
                        <abp-input asp-for="UserInfo.UserName" />
                        <abp-input asp-for="UserInfo.Name" />
                        <abp-input asp-for="UserInfo.Surname" />
                        <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                        @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<EditModalModel.UserInfoViewModel>())
                        {
                            if (!propertyInfo.Name.EndsWith("_Text"))
                            {
                                if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                                {
                                    if (propertyInfo.Type.IsEnum)
                                    {
                                        Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                    }
                                    <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                                label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                                autocomplete-api-url="@propertyInfo.Lookup.Url"
                                                autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                                autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                                autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                                autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                                autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                                autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                                }
                                else
                                {
                                    <abp-input type="@propertyInfo.GetInputType()"
                                               asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                               label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                               asp-format="@propertyInfo.GetInputFormatOrNull()"
                                               value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                                }
                            }
                        }
                        <abp-input asp-for="UserInfo.PhoneNumber" />
                        <abp-input asp-for="UserInfo.IsActive" />
                        <abp-input asp-for="UserInfo.LockoutEnabled" />
                    </abp-tab>
                    @if (Model.Roles.Any())
                    {
                        <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                            @for (var i = 0; i < Model.Roles.Length; i++)
                            {
                                var role = Model.Roles[i];
                                <abp-input asp-for="@role.IsAssigned"
                                           abp-id-name="@Model.Roles[i].IsAssigned"
                                           label="@role.GetShownName(HtmlEncoder, L.GetString("OU"))"
                                           disabled="@role.IsInheritedFromOu" />
                                <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                            }
                        </abp-tab>
                    }
    
                    @if (Model.OrganizationUnits.Any())
                    {
                        <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">
    
                            <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                                <ul class="jstree-container-ul jstree-children" role="group">
                                    @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                    {
                                        @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                        {
                                            Depth = 0,
                                            Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                            OrganizationUnits = Model.OrganizationUnits
                                        })
                                    }
                                </ul>
                            </div>
                            @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                            {
                                var organizationUnits = Model.OrganizationUnits[i];
                                <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                                <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                                <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                            }
                        </abp-tab>
                    }
                </abp-tabs>
            </abp-modal-body>
            <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
        </abp-modal>
    </form>
    <input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />
    
    

    For the models, you can just inherit from IdentityUserModalPageModel, IdentityUserModalPageModel and add your custom logic instead of writing all the model again.

    
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Identity;
    using Volo.Abp.Identity.Web.Pages.Identity.Users;
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(CreateModalModel))]
    public class MyCreateModalModel : CreateModalModel
    {
        public MyCreateModalModel(IIdentityUserAppService identityUserAppService) : base(identityUserAppService)
        {
        }
    
        public override async Task OnGetAsync()
        {
            await base.OnGetAsync(); // Keep base operations.
    
            // your own logic here
        }
    
        public override async Task<NoContentResult> OnPostAsync()
        {
            var result = await base.OnPostAsync();
    
            // your own logic here
    		
            return result;
        }
    }
    
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    how to prevent a user who has the privilege to manage the users from deleting the Admin user or Sys Role?

    You can replace and customize AppService

    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IdentityUserAppService))]
    public class MyIdenityUserAppService : IdentityUserAppService
    {
        // base ctor here
    
        public override  async Task DeleteAsync(Guid id)
        {
            var user = await UserManager.FindByIdAsync(id.ToString());
            if(user.UserName == "admin")
            {
                throw new Exception("can not delete admin");
            }
            (await UserManager.DeleteAsync(user)).CheckErrors();
        }
    }
    
  • User Avatar
    0
    hussein created

    thanks enisn

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11