diff --git a/Modules/UserManager/App_LocalResources/Impersonate.resx b/Modules/UserManager/App_LocalResources/Impersonate.resx
new file mode 100644
index 0000000..c760b64
--- /dev/null
+++ b/Modules/UserManager/App_LocalResources/Impersonate.resx
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Are you sure you want to impersonate this user account?
+
+
+ Delete User Account
+
+
+ Impersonate
+
+
+ You are about to impersonate another user account. <b>If you confirm</b>, the website will attempt to log you in as if the user themselves logged in. You will need to logout and log back in to restore your superuser access. <b>If you cancel</b>, nothing will happen.
+
+
+ <b>Technical Limitation:</b> If you are using another authentication provider other than the built-in DNN provider, this feature may or may not work, depending on the type of authentication you have installed/enabled.
+
+
+ Impersonate User Account
+
+
\ No newline at end of file
diff --git a/Modules/UserManager/App_LocalResources/Index.resx b/Modules/UserManager/App_LocalResources/Index.resx
index 192399b..d8e37dd 100644
--- a/Modules/UserManager/App_LocalResources/Index.resx
+++ b/Modules/UserManager/App_LocalResources/Index.resx
@@ -127,7 +127,7 @@
Create User
- Bulk Delete User
+ Bulk Delete Users
Create Role
@@ -187,7 +187,7 @@
Username
- User Roles
+ User's Roles
USERS
diff --git a/Modules/UserManager/App_LocalResources/Shared.resx b/Modules/UserManager/App_LocalResources/Shared.resx
index 2eae841..9073c02 100644
--- a/Modules/UserManager/App_LocalResources/Shared.resx
+++ b/Modules/UserManager/App_LocalResources/Shared.resx
@@ -180,4 +180,7 @@
Only a superuser is allowed to bulk delete user accounts
+
+ Cancel
+
\ No newline at end of file
diff --git a/Modules/UserManager/Controllers/UserManageController.cs b/Modules/UserManager/Controllers/UserManageController.cs
index b765e53..deaa9c0 100644
--- a/Modules/UserManager/Controllers/UserManageController.cs
+++ b/Modules/UserManager/Controllers/UserManageController.cs
@@ -534,5 +534,27 @@ public ActionResult PasswordResetLink(int itemId)
TempData["Message"] = UserRepository.SendPasswordResetLink(portalId, itemId, portalSettings);
return RedirectToAction("Index");
}
+
+ ///
+ /// Impersonate a user
+ ///
+ ///
+ ///
+ public ActionResult ImpersonateUserById(int itemId)
+ {
+ if (_currentUser.IsSuperUser)
+ {
+ var user = UserController.GetUserById(PortalSettings.PortalId, itemId);
+ if (user != null)
+ {
+ // Perform impersonation
+ UserController.UserLogin(PortalSettings.PortalId, user, PortalSettings.PortalName, Request.UserHostAddress, false);
+ }
+ return Redirect(Url.Content("~/"));
+ }
+ string errorMessage = Localization.GetString("NotPermissions.Text", ResourceFile);
+ ViewBag.ErrorMessage = errorMessage;
+ return View("Error");
+ }
}
}
diff --git a/Modules/UserManager/Module.css b/Modules/UserManager/Module.css
index a1a9207..87c7d6a 100644
--- a/Modules/UserManager/Module.css
+++ b/Modules/UserManager/Module.css
@@ -206,6 +206,7 @@
.checkbox {
font-size: 16px;
}
+
.admin-manager .checkbox {
margin-top: 20px;
}
@@ -320,6 +321,11 @@
margin-bottom: 25px;
}
+.mtb-2 {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
.pb10 {
padding-bottom: 10px !important;
}
@@ -726,4 +732,8 @@
line-height: 26px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
+}
+
+.AM-white, .AM-white a, .AM-white a:visited {
+ color: white;
}
\ No newline at end of file
diff --git a/Modules/UserManager/Properties/AssemblyInfo.cs b/Modules/UserManager/Properties/AssemblyInfo.cs
index 0badaa7..a4dfad1 100644
--- a/Modules/UserManager/Properties/AssemblyInfo.cs
+++ b/Modules/UserManager/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@
// Build Number
// Revision
//
-[assembly: AssemblyVersion("01.04.01")]
-[assembly: AssemblyFileVersion("01.04.01")]
+[assembly: AssemblyVersion("01.05.00")]
+[assembly: AssemblyFileVersion("01.05.00")]
diff --git a/Modules/UserManager/Providers/DataProviders/SqlDataProvider/01.05.00.SqlDataProvider b/Modules/UserManager/Providers/DataProviders/SqlDataProvider/01.05.00.SqlDataProvider
new file mode 100644
index 0000000..81a367f
--- /dev/null
+++ b/Modules/UserManager/Providers/DataProviders/SqlDataProvider/01.05.00.SqlDataProvider
@@ -0,0 +1,104 @@
+/************************************************************/
+/***** SqlDataProvider *****/
+/************************************************************/
+
+IF OBJECT_ID('{databaseOwner}{objectQualifier}UUM_GetUsers', 'P') IS NOT NULL
+BEGIN
+ EXEC('DROP PROCEDURE ' + '{databaseOwner}{objectQualifier}UUM_GetUsers');
+END
+GO
+
+CREATE PROCEDURE {databaseOwner}{objectQualifier}UUM_GetUsers
+ @PageIndex INT,
+ @PageSize INT,
+ @SearchTerm NVARCHAR(100) = NULL,
+ @SortColumn NVARCHAR(50) = 'UserID',
+ @SortOrder NVARCHAR(4) = 'ASC',
+ @IsSuperUser BIT = NULL,
+ @Authorised BIT = NULL,
+ @PortalId INT = NULL,
+ @Deleted BIT = NULL,
+ @AllUsers BIT = NULL,
+ @TotalRecords INT OUTPUT
+AS
+BEGIN
+ SET NOCOUNT ON;
+
+ DECLARE @Offset INT;
+ SET @Offset = (@PageIndex - 1) * @PageSize;
+
+ DECLARE @SortExpression NVARCHAR(100);
+ SET @SortExpression = QUOTENAME(@SortColumn) + ' ' + @SortOrder;
+
+ DECLARE @Results TABLE
+ (
+ UserID INT,
+ FirstName NVARCHAR(100),
+ Username NVARCHAR(100),
+ Email NVARCHAR(100),
+ DisplayName NVARCHAR(100),
+ IsSuperUser BIT,
+ RowNumber INT
+ );
+
+ -- Perform total count
+ IF @AllUsers = 0
+ BEGIN
+ SELECT @TotalRecords = COUNT(*)
+ FROM [dbo].[Users] u
+ LEFT JOIN [dbo].[UserPortals] up ON u.UserID = up.UserID
+ WHERE (LOWER(u.[UserName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[FirstName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[Email]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[DisplayName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%')
+ AND u.IsDeleted = 0
+ AND (@IsSuperUser IS NULL OR u.IsSuperUser = @IsSuperUser)
+ AND (@Deleted IS NULL OR up.IsDeleted = @Deleted)
+ AND (@Authorised IS NULL OR (up.Authorised = @Authorised AND up.IsDeleted = 0))
+ AND (@PortalId IS NULL OR up.PortalId = @PortalId);
+ END
+ ELSE
+ BEGIN
+ SELECT @TotalRecords = COUNT(*)
+ FROM [dbo].[Users] u
+ LEFT JOIN [dbo].[UserPortals] up ON u.UserID = up.UserID
+ WHERE (LOWER(u.[UserName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[FirstName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[Email]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[DisplayName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%')
+ AND (@PortalId IS NULL OR up.PortalId = @PortalId);
+ END;
+
+ -- Get paginated results
+ INSERT INTO @Results (UserID, FirstName, Username, Email, DisplayName, IsSuperUser, RowNumber)
+ SELECT u.UserID, u.FirstName, u.Username, u.Email, u.DisplayName, u.IsSuperUser,
+ ROW_NUMBER() OVER (
+ ORDER BY
+ CASE WHEN @SortOrder = 'ASC' AND @SortColumn = 'FirstName' THEN u.FirstName END ASC,
+ CASE WHEN @SortOrder = 'DESC' AND @SortColumn = 'FirstName' THEN u.FirstName END DESC,
+ CASE WHEN @SortOrder = 'ASC' AND @SortColumn = 'Username' THEN u.UserName END ASC,
+ CASE WHEN @SortOrder = 'DESC' AND @SortColumn = 'Username' THEN u.UserName END DESC,
+ CASE WHEN @SortOrder = 'ASC' AND @SortColumn = 'Email' THEN u.Email END ASC,
+ CASE WHEN @SortOrder = 'DESC' AND @SortColumn = 'Email' THEN u.Email END DESC,
+ CASE WHEN @SortOrder = 'ASC' AND @SortColumn = 'DisplayName' THEN u.DisplayName END ASC,
+ CASE WHEN @SortOrder = 'DESC' AND @SortColumn = 'DisplayName' THEN u.DisplayName END DESC
+ ) AS RowNumber
+ FROM [dbo].[Users] u
+ LEFT JOIN [dbo].[UserPortals] up ON u.UserID = up.UserID
+ WHERE
+ (LOWER(u.[UserName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[FirstName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[Email]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%' OR
+ LOWER(u.[DisplayName]) COLLATE Latin1_General_CI_AI LIKE '%' + LOWER(@SearchTerm) COLLATE Latin1_General_CI_AI + '%')
+ AND u.IsDeleted = 0
+ AND (@IsSuperUser IS NULL OR u.IsSuperUser = @IsSuperUser)
+ AND (@Deleted IS NULL OR up.IsDeleted = @Deleted)
+ AND (@Authorised IS NULL OR (up.Authorised = @Authorised AND up.IsDeleted = 0))
+ AND (@PortalId IS NULL OR up.PortalId = @PortalId)
+ ORDER BY RowNumber;
+
+ -- Return paginated results
+ SELECT UserID, FirstName, Username, Email, DisplayName, IsSuperUser
+ FROM @Results
+ WHERE RowNumber BETWEEN (@Offset + 1) AND (@Offset + @PageSize);
+END;
\ No newline at end of file
diff --git a/Modules/UserManager/Upendo.Modules.UserManager.csproj b/Modules/UserManager/Upendo.Modules.UserManager.csproj
index 231dde6..5d525fc 100644
--- a/Modules/UserManager/Upendo.Modules.UserManager.csproj
+++ b/Modules/UserManager/Upendo.Modules.UserManager.csproj
@@ -1,4 +1,4 @@
-
+
@@ -13,7 +13,7 @@
Properties
Upendo.Modules.UserManager
Upendo.Modules.UserManager
- v4.7.2
+ v4.8
false
@@ -75,10 +75,6 @@
-
-
-
-
@@ -176,6 +172,7 @@
+
@@ -186,6 +183,9 @@
+
+
+
14.0
diff --git a/Modules/UserManager/Upendo.UserManager.dnn b/Modules/UserManager/Upendo.UserManager.dnn
index ce6de2d..b42899a 100644
--- a/Modules/UserManager/Upendo.UserManager.dnn
+++ b/Modules/UserManager/Upendo.UserManager.dnn
@@ -1,7 +1,7 @@
-
+
Upendo DNN User Manager
The Upendo DNN User Manager empowers authorized end-users in your DNN website to be able to manage user accounts and their assigned security roles.
]]>
DesktopModules/MVC/Upendo.Modules.UserManager/Images/logo.png
@@ -60,7 +60,7 @@
Upendo.Modules.UserManager.Components.UserManagerController, Upendo.Modules.UserManager
[DESKTOPMODULEID]
- 01.00.00,01.01.00,01.01.01,01.02.00,01.03.00,01.04.00,01.04.01
+ 01.00.00,01.01.00,01.01.01,01.02.00,01.03.00,01.04.00,01.04.01,01.05.00
@@ -69,7 +69,7 @@
Upendo.Modules.UserManager.dll
bin
- 01.04.01
+ 01.05.00
@@ -89,10 +89,15 @@
01.01.01.SqlDataProvider
01.01.01
+
diff --git a/Modules/UserManager/Upendo.UserManager_Symbols.dnn b/Modules/UserManager/Upendo.UserManager_Symbols.dnn
index d2efd6e..4f68b39 100644
--- a/Modules/UserManager/Upendo.UserManager_Symbols.dnn
+++ b/Modules/UserManager/Upendo.UserManager_Symbols.dnn
@@ -1,7 +1,7 @@
-
+
Upendo DNN User Manager Symbols
@@ -14,7 +14,7 @@
True
- Upendo.Modules.UserManager
+ Upendo.Modules.UserManager
diff --git a/Modules/UserManager/Utility/Functions.cs b/Modules/UserManager/Utility/Functions.cs
index 40a203f..2e97bcc 100644
--- a/Modules/UserManager/Utility/Functions.cs
+++ b/Modules/UserManager/Utility/Functions.cs
@@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using DotNetNuke.Instrumentation;
using DotNetNuke.Services.Localization;
using DotNetNuke.Security.Roles;
+using System.Globalization;
+using System.Text;
namespace Upendo.Modules.UserManager.Utility
{
@@ -127,7 +129,7 @@ public static DataTableResponse GetUsersProcedure(Pagination pagination,
using (var connection = new SqlConnection(connectionString))
{
var pageIndex = pagination.PageIndex == 0 ? 1 : pagination.PageIndex;
- var search = string.IsNullOrWhiteSpace(pagination.Search) ? "" : pagination.Search;
+ var search = RemoveDiacritics(string.IsNullOrWhiteSpace(pagination.Search) ? "" : pagination.Search.Replace(" ", string.Empty).ToLower());
var totalRecordsParameter = new SqlParameter("@TotalRecords", SqlDbType.Int);
totalRecordsParameter.Direction = ParameterDirection.Output;
var command = new SqlCommand("UUM_GetUsers", connection);
@@ -254,5 +256,22 @@ public static bool HasPermission(DotNetNuke.UI.Modules.ModuleInstanceContext Mod
ModulePermissionCollection permissions = ModulePermissionController.GetModulePermissions(moduleId, tabId);
return ModulePermissionController.HasModulePermission(permissions, "EDIT");
}
+
+ private static string RemoveDiacritics(string text)
+ {
+ var normalizedString = text.Normalize(NormalizationForm.FormD);
+ var stringBuilder = new StringBuilder();
+
+ foreach (var c in normalizedString)
+ {
+ var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
+ if (unicodeCategory != UnicodeCategory.NonSpacingMark)
+ {
+ stringBuilder.Append(c);
+ }
+ }
+
+ return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
+ }
}
}
\ No newline at end of file
diff --git a/Modules/UserManager/Utility/UserRepository.cs b/Modules/UserManager/Utility/UserRepository.cs
index 6d04d96..550eeea 100644
--- a/Modules/UserManager/Utility/UserRepository.cs
+++ b/Modules/UserManager/Utility/UserRepository.cs
@@ -286,7 +286,6 @@ public static void EditUser(int portalId, UserViewModel user)
userInfo.FirstName = user.FirstName;
userInfo.LastName = user.LastName;
userInfo.Email = user.Email;
- userInfo.Username = user.Username;
userInfo.DisplayName = user.DisplayName;
userInfo.PortalID = portalId;
userInfo.IsSuperUser = currentUser.IsSuperUser ? user.IsSuperUser : false;
@@ -302,6 +301,10 @@ public static void EditUser(int portalId, UserViewModel user)
userInfo.Roles[userInfo.Roles.Count() - 1] = user.NewUserRol;
}
UserController.UpdateUser(portalId, userInfo);
+ if (userInfo.Username != user.Username)
+ {
+ UserController.ChangeUsername(user.UserId, user.Username);
+ }
}
///
diff --git a/Modules/UserManager/Views/UserManage/Index.cshtml b/Modules/UserManager/Views/UserManage/Index.cshtml
index 143d849..0b3ffe0 100644
--- a/Modules/UserManager/Views/UserManage/Index.cshtml
+++ b/Modules/UserManager/Views/UserManage/Index.cshtml
@@ -26,10 +26,11 @@