diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml
index 6cc077a663..2e7e7f3f4c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml
@@ -2,6 +2,10 @@
@model ApplicationMenu
@foreach (var menuItem in Model.Items)
{
+ var elementId = string.IsNullOrEmpty(menuItem.ElementId) ? string.Empty : $"id=\"{menuItem.ElementId}\"";
+ var cssClass = string.IsNullOrEmpty(menuItem.CssClass) ? string.Empty : menuItem.CssClass;
+ var disabled = menuItem.IsDisabled ? "disabled" : string.Empty;
+
if (menuItem.IsLeaf)
{
if (menuItem.Url == null)
@@ -9,7 +13,7 @@
continue;
}
-
@if (menuItem.Icon != null)
{
@@ -29,7 +33,9 @@
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml
index 8ba998785e..c30c7b6a0b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml
@@ -11,16 +11,20 @@
-
+
@if (Model.Items.Any())
{
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs
index 354cfd3b00..aa4003c5f0 100644
--- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs
+++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs
@@ -37,7 +37,7 @@ namespace Volo.Abp.UI.Navigation
/// Default value: 1000.
///
public int Order { get; set; }
-
+
///
/// The URL to navigate when this menu item is selected.
///
@@ -65,7 +65,7 @@ namespace Volo.Abp.UI.Navigation
/// Can be used to disable this menu item.
///
public bool IsDisabled { get; set; }
-
+
///
[NotNull]
public IList Items { get; }
@@ -75,14 +75,27 @@ namespace Volo.Abp.UI.Navigation
///
public object CustomData { get; set; }
+ ///
+ /// Can be used to render the element with a specific Id for DOM selections.
+ ///
+ public string ElementId { get; set; }
+
+ ///
+ /// Can be used to render the element with extra CSS classes.
+ ///
+ public string CssClass { get; set; }
+
+
public ApplicationMenuItem(
- [NotNull] string name,
+ [NotNull] string name,
[NotNull] string displayName,
string url = null,
string icon = null,
int order = DefaultOrder,
object customData = null,
- string target = null)
+ string target = null,
+ string elementId = null,
+ string cssClass = null)
{
Check.NotNullOrWhiteSpace(name, nameof(name));
Check.NotNullOrWhiteSpace(displayName, nameof(displayName));
@@ -94,6 +107,8 @@ namespace Volo.Abp.UI.Navigation
Order = order;
CustomData = customData;
Target = target;
+ ElementId = elementId;
+ CssClass = cssClass;
Items = new List();
}
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
index c324d667ea..9c8944176b 100644
--- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
@@ -33,6 +33,7 @@
"PagerNext": "Next",
"PagerPrevious": "Previous",
"PagerInfo": "Showing {0} to {1} of {2} entries.",
- "DatatableActionDropdownDefaultText": "Actions"
+ "DatatableActionDropdownDefaultText": "Actions",
+ "ChangePassword": "Change password"
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
index 7086210144..f85e255058 100644
--- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
@@ -33,6 +33,7 @@
"PagerNext": "Sonraki",
"PagerPrevious": "Önceki",
"PagerInfo": "{2} kayıttan {0} ile {1} arası gösteriliyor.",
- "DatatableActionDropdownDefaultText": "İşlemler"
+ "DatatableActionDropdownDefaultText": "İşlemler",
+ "ChangePassword": "Şifre değiştir"
}
}
\ No newline at end of file
diff --git a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
index ef5e661771..d021cbabe1 100644
--- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
+++ b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
@@ -10,7 +10,7 @@ namespace Volo.Abp.Account.Web
{
public AbpAccountUserMenuContributor()
{
-
+
}
public Task ConfigureMenuAsync(MenuConfigurationContext context)
@@ -22,6 +22,8 @@ namespace Volo.Abp.Account.Web
var l = context.ServiceProvider.GetRequiredService>();
+ context.Menu.AddItem(new ApplicationMenuItem("Account.ChangePassword", l["ChangePassword"], icon: "fa fa-key", url: "#", elementId: "abp-account-change-password"));
+
context.Menu.AddItem(new ApplicationMenuItem("Account.Logout", l["Logout"], url: "/Account/Logout", icon: "fa fa-power-off", order: int.MaxValue - 1000));
return Task.CompletedTask;
diff --git a/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json b/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json
index a318da87a2..b56354053c 100644
--- a/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json
+++ b/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json
@@ -9,7 +9,7 @@
"UseAnotherServiceToLogin": "Başka bir servisle giriş yap",
"UserLockedOutMessage": "Kullanıcı hesabı hatalı giriş denemeleri nedeniyle kilitlenmiştir. Lütfen bir süre bekleyip tekrar deneyin.",
"InvalidUserNameOrPassword": "Kullanıcı adı ya da şifre geçersiz!",
- "LoginIsNotAllowed": "You are not allowed to login! E-posta adresinizi ya da telefon numaranızı doğrulamanız gerekiyor.",
+ "LoginIsNotAllowed": "Giriş yapamazsınız! E-posta adresinizi ya da telefon numaranızı doğrulamanız gerekiyor.",
"SelfRegistrationDisabledMessage": "Bu uygulama için kullanıcıların kendi kendilerine kaydolmaları engellenmiştir. Yeni bir kullanıcı kaydetmek için lütfen uygulama yöneticisi ile iletişime geçin."
}
}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs
index 50ea282f15..39d510f2c1 100644
--- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityUserAppService.cs
@@ -19,5 +19,7 @@ namespace Volo.Abp.Identity
Task FindByUsernameAsync(string username);
Task FindByEmailAsync(string email);
+
+ Task ChangePasswordAsync(string currentPassword, string newPassword);
}
}
diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
index 3f28afb3f5..18e5748c6d 100644
--- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
@@ -113,7 +113,6 @@ namespace Volo.Abp.Identity
await _permissionAppServiceHelper.UpdateAsync(UserPermissionValueProvider.ProviderName, id.ToString(), input);
}
- [Authorize(IdentityPermissions.Users.Default)]
public async Task FindByUsernameAsync(string username)
{
return ObjectMapper.Map(
@@ -121,7 +120,6 @@ namespace Volo.Abp.Identity
);
}
- [Authorize(IdentityPermissions.Users.Default)]
public async Task FindByEmailAsync(string email)
{
return ObjectMapper.Map(
@@ -129,6 +127,17 @@ namespace Volo.Abp.Identity
);
}
+ public async Task ChangePasswordAsync(string currentPassword, string newPassword)
+ {
+ if (!CurrentUser.Id.HasValue)
+ {
+ throw new AbpException("Current user Id is null!");
+ }
+
+ var currentUser = await _userManager.GetByIdAsync(CurrentUser.Id.Value);
+ (await _userManager.ChangePasswordAsync(currentUser, currentPassword, newPassword)).CheckErrors();
+ }
+
private async Task UpdateUserByInput(IdentityUser user, IdentityUserCreateOrUpdateDtoBase input)
{
(await _userManager.SetEmailAsync(user, input.Email)).CheckErrors();
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 a1ee4371d4..c906f523b1 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
@@ -25,6 +25,7 @@
"Identity.UserLockedOut": "User is locked out.",
"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.UserNotInRole": "User is not in role '{0}'.",
+ "Identity.PasswordConfirmationFailed": "Password does not match the confirm password."
}
}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json
index d2401b47a4..96cf510ff8 100644
--- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json
+++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json
@@ -25,6 +25,7 @@
"Identity.UserLockedOut": "Kullanıcı hesabı kilitlenmiş.",
"Identity.UserLockoutNotEnabled": "Bu kullanıcı için hesap kilitleme etkin değil.",
"Identity.UserNameNotFound": "{0} kullanıcısı bulunamadı.",
- "Identity.UserNotInRole": "Kullanıcı '{0}' rolünde değil."
+ "Identity.UserNotInRole": "Kullanıcı '{0}' rolünde değil.",
+ "Identity.PasswordConfirmationFailed": "Yeni şifre ile onay şifresi uyuşmuyor."
}
}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs
index 761f98d6bf..2d6ad778ae 100644
--- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs
+++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs
@@ -64,7 +64,6 @@ namespace Volo.Abp.Identity
return _userAppService.UpdatePermissionsAsync(id, input);
}
- //todo: add authorize attrbutes on the corresponding methods.
[HttpGet]
public virtual Task FindByUsernameAsync(string username)
{
@@ -76,5 +75,10 @@ namespace Volo.Abp.Identity
{
return _userAppService.FindByEmailAsync(email);
}
+
+ public Task ChangePasswordAsync(string currentPassword, string newPassword)
+ {
+ return _userAppService.ChangePasswordAsync(currentPassword, newPassword);
+ }
}
}
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
index 62888d0abe..5444840fa5 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
@@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
+using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
+using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity.Localization;
using Volo.Abp.Identity.Web.Navigation;
@@ -65,6 +67,14 @@ namespace Volo.Abp.Identity.Web
options.Conventions.AuthorizePage("/Identity/Roles/CreateModal", IdentityPermissions.Roles.Create);
options.Conventions.AuthorizePage("/Identity/Roles/EditModal", IdentityPermissions.Roles.Update);
});
+
+ Configure(options =>
+ {
+ options
+ .ScriptBundles
+ .Get(StandardBundles.Scripts.Global)
+ .AddFiles("/Pages/Identity/Shared/change-password-modal.js");
+ });
}
}
}
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 d0757f5a54..e63e8fb4b2 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
@@ -22,6 +22,10 @@
"NewRole": "New role",
"RoleName": "Role name",
"CreationTime": "Creation time",
- "Permissions": "Permissions"
+ "Permissions": "Permissions",
+ "DisplayName:CurrentPassword": "Current password",
+ "DisplayName:NewPassword": "New password",
+ "DisplayName:NewPasswordConfirm": "Confirm new password",
+ "PasswordChangedMessage": "Your password has been changed successfully."
}
}
\ No newline at end of file
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 f330cf5b70..7484851424 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
@@ -22,6 +22,10 @@
"NewRole": "Yeni rol",
"RoleName": "Rol adı",
"CreationTime": "Oluşturma zamanı",
- "Permissions": "İzinler"
+ "Permissions": "İzinler",
+ "DisplayName:CurrentPassword": "Mevcut şifre",
+ "DisplayName:NewPassword": "Yeni şifre",
+ "DisplayName:NewPasswordConfirm": "Yeni şifre (tekrar)",
+ "PasswordChangedMessage": "Şifreniz başarıyla değiştirildi."
}
}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml
new file mode 100644
index 0000000000..54bae13cbe
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml
@@ -0,0 +1,20 @@
+@page
+@using Microsoft.AspNetCore.Mvc.Localization
+@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
+@using Volo.Abp.Identity.Localization
+@using Volo.Abp.Identity.Web.Pages.Identity.Shared
+@model ChangePasswordModal
+@inject IHtmlLocalizer L
+@{
+ Layout = null;
+}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml.cs
new file mode 100644
index 0000000000..0e753edd6c
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/ChangePasswordModal.cshtml.cs
@@ -0,0 +1,61 @@
+using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Localization;
+using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
+using Volo.Abp.Identity.Localization;
+
+namespace Volo.Abp.Identity.Web.Pages.Identity.Shared
+{
+ public class ChangePasswordModal : AbpPageModel
+ {
+ [BindProperty]
+ public ChangePasswordInfoModel ChangePasswordInfoModel { get; set; }
+
+ private readonly IIdentityUserAppService _userAppService;
+ private readonly IStringLocalizer _localizer;
+
+ public ChangePasswordModal(IIdentityUserAppService userAppService,
+ IStringLocalizer localizer)
+ {
+ _userAppService = userAppService;
+ _localizer = localizer;
+ }
+
+ public async Task OnPostAsync()
+ {
+ ValidateModel();
+
+ if (ChangePasswordInfoModel.NewPassword != ChangePasswordInfoModel.NewPasswordConfirm)
+ {
+ throw new UserFriendlyException(_localizer.GetString("Identity.PasswordConfirmationFailed").Value);
+ }
+
+ await _userAppService.ChangePasswordAsync(ChangePasswordInfoModel.CurrentPassword,
+ ChangePasswordInfoModel.NewPassword);
+
+ return NoContent();
+ }
+ }
+
+ public class ChangePasswordInfoModel
+ {
+ [Required]
+ [StringLength(IdentityUserConsts.MaxPasswordLength)]
+ [Display(Name = "DisplayName:CurrentPassword")]
+ [DataType(DataType.Password)]
+ public string CurrentPassword { get; set; }
+
+ [Required]
+ [StringLength(IdentityUserConsts.MaxPasswordLength)]
+ [Display(Name = "DisplayName:NewPassword")]
+ [DataType(DataType.Password)]
+ public string NewPassword { get; set; }
+
+ [Required]
+ [StringLength(IdentityUserConsts.MaxPasswordLength)]
+ [Display(Name = "DisplayName:NewPasswordConfirm")]
+ [DataType(DataType.Password)]
+ public string NewPasswordConfirm { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/change-password-modal.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/change-password-modal.js
new file mode 100644
index 0000000000..c377ea718b
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/change-password-modal.js
@@ -0,0 +1,18 @@
+(function ($) {
+
+ var l = abp.localization.getResource('AbpIdentity');
+ var _changePasswordModal = new abp.ModalManager(abp.appPath + 'Identity/Shared/ChangePasswordModal');
+
+ $(function () {
+
+ $("#abp-account-change-password").click(function (e) {
+ e.preventDefault();
+ _changePasswordModal.open();
+ });
+
+ _changePasswordModal.onResult(function () {
+ abp.message.success(l("PasswordChangedMessage"));
+ });
+ });
+
+})(jQuery);
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj b/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj
index a2b78b5495..e86149c47f 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj
@@ -37,6 +37,7 @@
+