diff --git a/DigitalLearningSolutions.Data.Tests/Helpers/UserPermissionsHelperTests.cs b/DigitalLearningSolutions.Data.Tests/Helpers/UserPermissionsHelperTests.cs new file mode 100644 index 0000000000..9134071bb4 --- /dev/null +++ b/DigitalLearningSolutions.Data.Tests/Helpers/UserPermissionsHelperTests.cs @@ -0,0 +1,96 @@ +namespace DigitalLearningSolutions.Data.Tests.Helpers +{ + using DigitalLearningSolutions.Data.Helpers; + using DigitalLearningSolutions.Data.Tests.TestHelpers; + using FluentAssertions; + using NUnit.Framework; + + public class UserPermissionsHelperTests + { + + [Test] + public void LoggedInAdminCanDeactivateUser_centre_manager_should_not_be_able_to_deactivate_their_own_account() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isCentreManager: true); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isCentreManager: true); + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeFalse(); + } + + [Test] + public void LoggedInAdminCanDeactivateUser_centre_manager_should_not_be_able_to_deactivate_other_centre_manager() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isCentreManager: true, isUserAdmin: false); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 2, isCentreManager: true, isUserAdmin: false); + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeFalse(); + } + + [Test] + public void LoggedInAdminCanDeactivateUser_centre_manager_should_not_be_able_to_deactivate_super_admin_account() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isUserAdmin: true); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 2, isCentreManager: true, isUserAdmin: false); + + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeFalse(); + } + + [Test] + public void LoggedInAdminCanDeactivateUser_super_admin_should_not_be_able_to_deactivate_their_own_account() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isUserAdmin: true); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isUserAdmin: true); + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeFalse(); + } + + [Test] + public void LoggedInAdminCanDeactivateUser_super_admin_should_be_able_to_deactivate_other_super_admin() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isUserAdmin: true); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 2, isUserAdmin: true); + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeTrue(); + } + + [Test] + public void LoggedInAdminCanDeactivateUser_super_admin_should_be_able_to_deactivate_centre_manager() + { + // Given + var adminUser = UserTestHelper.GetDefaultAdminUser(id: 1, isCentreManager: true); + var loggedInAdminUser = UserTestHelper.GetDefaultAdminUser(id: 2, isUserAdmin: true); + + // When + var result = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + + // Then + result.Should().BeTrue(); + } + } +} diff --git a/DigitalLearningSolutions.Data/Helpers/UserPermissionsHelper.cs b/DigitalLearningSolutions.Data/Helpers/UserPermissionsHelper.cs new file mode 100644 index 0000000000..3550a1f5e0 --- /dev/null +++ b/DigitalLearningSolutions.Data/Helpers/UserPermissionsHelper.cs @@ -0,0 +1,24 @@ +namespace DigitalLearningSolutions.Data.Helpers +{ + using DigitalLearningSolutions.Data.Models.User; + + public static class UserPermissionsHelper + { + public static bool LoggedInAdminCanDeactivateUser(AdminUser adminUser, AdminUser loggedInAdminUser) + { + if (loggedInAdminUser.IsUserAdmin) + { + return adminUser.Id != loggedInAdminUser.Id; + } + + if (loggedInAdminUser.IsCentreManager) + { + return !adminUser.IsUserAdmin + && !adminUser.IsCentreManager + && adminUser.Id != loggedInAdminUser.Id; + } + + return false; + } + } +} diff --git a/DigitalLearningSolutions.Web.Tests/ViewComponents/CurrentFiltersViewComponentTests.cs b/DigitalLearningSolutions.Web.Tests/ViewComponents/CurrentFiltersViewComponentTests.cs index 06c2b7aa64..9093070fc9 100644 --- a/DigitalLearningSolutions.Web.Tests/ViewComponents/CurrentFiltersViewComponentTests.cs +++ b/DigitalLearningSolutions.Web.Tests/ViewComponents/CurrentFiltersViewComponentTests.cs @@ -2,6 +2,7 @@ { using System.Collections.Generic; using DigitalLearningSolutions.Data.Models.User; + using DigitalLearningSolutions.Data.Tests.TestHelpers; using DigitalLearningSolutions.Web.Helpers.FilterOptions; using DigitalLearningSolutions.Web.ViewComponents; using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; @@ -42,7 +43,8 @@ public void CurrentFiltersViewComponent_selects_expected_filters_to_display() categories, searchString, "CategoryName|CategoryName|Word╡Role|IsCentreAdmin|true", - 1 + 1, + UserTestHelper.GetDefaultAdminUser() ); var expectedAppliedFilters = new List { diff --git a/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModelTests.cs b/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModelTests.cs index ef135715c0..850f4abceb 100644 --- a/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModelTests.cs +++ b/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModelTests.cs @@ -40,7 +40,8 @@ public void Centre_administrators_should_default_to_returning_the_first_ten_admi new List(), null, null, - 1 + 1, + UserTestHelper.GetDefaultAdminUser() ); model.Admins.Count().Should().Be(10); @@ -56,7 +57,8 @@ public void Centre_administrators_should_correctly_return_the_second_page_of_adm new List(), null, null, - 2 + 2, + UserTestHelper.GetDefaultAdminUser() ); model.Admins.Count().Should().Be(5); @@ -95,7 +97,8 @@ public void Centre_Administrators_filters_should_be_set() new List(), null, null, - 2 + 2, + UserTestHelper.GetDefaultAdminUser() ); // Then diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs index 363238b65b..74ea6d7150 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs @@ -1,7 +1,5 @@ namespace DigitalLearningSolutions.Web.Controllers.TrackingSystem.Centre.Administrator { - using System.Collections.Generic; - using System.Linq; using DigitalLearningSolutions.Data.DataServices; using DigitalLearningSolutions.Data.DataServices.UserDataService; using DigitalLearningSolutions.Data.Enums; @@ -16,6 +14,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.FeatureManagement.Mvc; + using System.Collections.Generic; + using System.Linq; [FeatureGate(FeatureFlags.RefactoredTrackingSystem)] [Authorize(Policy = CustomPolicies.UserCentreManager)] @@ -61,6 +61,9 @@ public IActionResult Index( var centreId = User.GetCentreId(); var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); var categories = GetCourseCategories(centreId); + var loggedInUserId = User.GetAdminId(); + var loggedInAdminUser = userDataService.GetAdminUserById(loggedInUserId!.GetValueOrDefault()); + var model = new CentreAdministratorsViewModel( centreId, @@ -68,7 +71,8 @@ public IActionResult Index( categories, searchString, filterBy, - page + page, + loggedInAdminUser! ); Response.UpdateOrDeleteFilterCookie(AdminFilterCookieName, filterBy); @@ -80,9 +84,17 @@ public IActionResult Index( public IActionResult AllAdmins() { var centreId = User.GetCentreId(); + var loggedInUserId = User.GetAdminId(); + var loggedInAdminUser = userDataService.GetAdminUserById(loggedInUserId!.GetValueOrDefault()); + + var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); var categories = GetCourseCategories(centreId); - var model = new AllAdminsViewModel(adminUsersAtCentre, categories); + var model = new AllAdminsViewModel( + adminUsersAtCentre, + categories, + loggedInAdminUser! + ); return View("AllAdmins", model); } diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/AllAdminsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/AllAdminsViewModel.cs index f3405657f4..84b034608a 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/AllAdminsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/AllAdminsViewModel.cs @@ -10,9 +10,12 @@ public class AllAdminsViewModel : BaseJavaScriptFilterableViewModel { public readonly IEnumerable Admins; - public AllAdminsViewModel(IEnumerable adminUsers, IEnumerable categories) + public AllAdminsViewModel(IEnumerable adminUsers, + IEnumerable categories, + AdminUser loggedInAdminUser) + { - Admins = adminUsers.Select(au => new SearchableAdminViewModel(au, null)); + Admins = adminUsers.Select(au => new SearchableAdminViewModel(au, loggedInAdminUser, 1)); Filters = new[] { diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModel.cs index d406dacb4f..768334d77c 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/CentreAdministratorsViewModel.cs @@ -14,7 +14,8 @@ public CentreAdministratorsViewModel( IEnumerable categories, string? searchString, string? filterBy, - int page + int page, + AdminUser loggedInAdminUser ) : base(searchString, page, true, filterBy: filterBy, searchLabel: "Search administrators") { CentreId = centreId; @@ -29,7 +30,7 @@ int page SetTotalPages(); var paginatedItems = GetItemsOnCurrentPage(filteredItems); var returnPage = string.IsNullOrWhiteSpace(searchString) ? page : 1; - Admins = paginatedItems.Select(adminUser => new SearchableAdminViewModel(adminUser, returnPage)); + Admins = paginatedItems.Select(adminUser => new SearchableAdminViewModel(adminUser, loggedInAdminUser, returnPage)); Filters = new[] { diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/SearchableAdminViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/SearchableAdminViewModel.cs index eed2086528..2ab792b3f6 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/SearchableAdminViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/Administrator/SearchableAdminViewModel.cs @@ -1,19 +1,24 @@ namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.Administrator { + using DigitalLearningSolutions.Data.Helpers; using DigitalLearningSolutions.Data.Models.User; using DigitalLearningSolutions.Web.Helpers; using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; public class SearchableAdminViewModel : BaseFilterableViewModel { - public SearchableAdminViewModel(AdminUser adminUser, int? page) + public readonly bool CanShowDeactivateAdminButton; + + public SearchableAdminViewModel(AdminUser adminUser, AdminUser loggedInAdminUser, int? page) { Id = adminUser.Id; Name = adminUser.SearchableName; CategoryName = adminUser.CategoryName ?? "All"; EmailAddress = adminUser.EmailAddress; IsLocked = adminUser.IsLocked; - IsCentreManager = adminUser.IsCentreManager; + + CanShowDeactivateAdminButton = UserPermissionsHelper.LoggedInAdminCanDeactivateUser(adminUser, loggedInAdminUser); + Tags = FilterableTagHelper.GetCurrentTagsForAdminUser(adminUser); Page = page; } @@ -32,8 +37,6 @@ public SearchableAdminViewModel(AdminUser adminUser, int? page) public bool IsLocked { get; set; } - public bool IsCentreManager { get; set; } - public int? Page { get; set; } } } diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Administrator/_SearchableAdminCard.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Administrator/_SearchableAdminCard.cshtml index d2e4c7fee1..877d287515 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Administrator/_SearchableAdminCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Administrator/_SearchableAdminCard.cshtml @@ -54,7 +54,7 @@ Manage roles } - @if (!Model.IsCentreManager) { + @if (Model.CanShowDeactivateAdminButton) {