Skip to content

Commit 4211936

Browse files
authored
Merge pull request #2799 from TechnologyEnhancedLearning/Develop/Features/TD-4383-Warncentreadminsthatactiveadminaccountexistswheninactivatingdelegateaccount
TD-4383 Warn centre admins that active admin account exists when inactivating delegate account
2 parents 5a1826b + 4210151 commit 4211936

File tree

7 files changed

+265
-29
lines changed

7 files changed

+265
-29
lines changed

DigitalLearningSolutions.Data/DataServices/UserDataService/DelegateUserDataService.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,15 @@ public void DeactivateDelegateUser(int delegateId)
389389
new { delegateId }
390390
);
391391
}
392-
392+
public void DeactivateAdminAccount(int userId ,int centreId)
393+
{
394+
connection.Execute(
395+
@"UPDATE AdminAccounts
396+
SET Active =0
397+
WHERE UserID = @userId AND CentreID = @centreId",
398+
new { userId, centreId }
399+
);
400+
}
393401
public void ActivateDelegateUser(int delegateId)
394402
{
395403
connection.Execute(
@@ -419,7 +427,15 @@ FROM Candidates
419427
new { delegateId }
420428
).Single();
421429
}
422-
430+
public int? CheckDelegateIsActive(int delegateId)
431+
{
432+
return connection.Query<int?>(
433+
@"SELECT CandidateID
434+
FROM Candidates
435+
WHERE CandidateID = @delegateId AND Active =1",
436+
new { delegateId }
437+
).FirstOrDefault();
438+
}
423439
public void SetDelegateUserLearningHubAuthId(int delegateId, int learningHubAuthId)
424440
{
425441
connection.Execute(

DigitalLearningSolutions.Data/DataServices/UserDataService/UserDataService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ int centreId
291291
public bool PrimaryEmailInUseAtCentres(string email);
292292

293293
public int? GetUserIdFromLearningHubAuthId(int learningHubAuthId);
294+
void DeactivateAdminAccount(int userId, int centreId);
295+
int? CheckDelegateIsActive(int delegateId);
294296
}
295297

296298
public partial class UserDataService : IUserDataService
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+

2+
3+
namespace DigitalLearningSolutions.Web.Controllers.TrackingSystem.Delegates
4+
{
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using DigitalLearningSolutions.Data.Enums;
8+
using DigitalLearningSolutions.Data.Models.User;
9+
using DigitalLearningSolutions.Web.Attributes;
10+
using DigitalLearningSolutions.Web.Helpers;
11+
using DigitalLearningSolutions.Web.Models.Enums;
12+
using DigitalLearningSolutions.Web.ServiceFilter;
13+
using DigitalLearningSolutions.Web.Services;
14+
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.DeactivateDelegate;
15+
using Microsoft.AspNetCore.Authorization;
16+
using Microsoft.AspNetCore.Mvc;
17+
using Microsoft.FeatureManagement.Mvc;
18+
19+
20+
[FeatureGate(FeatureFlags.RefactoredTrackingSystem)]
21+
[Authorize(Policy = CustomPolicies.UserCentreAdmin)]
22+
[ServiceFilter(typeof(VerifyAdminUserCanAccessDelegateUser))]
23+
[Route("TrackingSystem/Delegates/{delegateId:int}/Deactivate")]
24+
[SetDlsSubApplication(nameof(DlsSubApplication.TrackingSystem))]
25+
[SetSelectedTab(nameof(NavMenuTab.Delegates))]
26+
public class DeactivateDelegateController : Controller
27+
{
28+
private readonly IUserService userService;
29+
public DeactivateDelegateController(
30+
IUserService userService
31+
)
32+
{
33+
this.userService = userService;
34+
}
35+
[HttpGet]
36+
public IActionResult Index(int delegateId)
37+
{
38+
var checkDelegate = userService.CheckDelegateIsActive(delegateId);
39+
if (checkDelegate != delegateId)
40+
{
41+
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 410 });
42+
}
43+
var centreId = User.GetCentreId();
44+
var delegateEntity = userService.GetDelegateById(delegateId)!;
45+
var userEntity = userService.GetUserById(delegateEntity.DelegateAccount.UserId);
46+
var adminAccount = userEntity!.GetCentreAccountSet(centreId)?.AdminAccount;
47+
var roles = GetRoles(adminAccount, userEntity);
48+
var model = new DeactivateDelegateAccountViewModel
49+
{
50+
DelegateId = delegateId,
51+
Name = delegateEntity.UserAccount.FirstName + " " + delegateEntity.UserAccount.LastName,
52+
Roles = roles,
53+
Email = delegateEntity.UserAccount.PrimaryEmail,
54+
UserId = delegateEntity.UserAccount.Id
55+
};
56+
return View(model);
57+
}
58+
59+
[HttpPost]
60+
public IActionResult Index(DeactivateDelegateAccountViewModel deactivateDelegateAccountViewModel)
61+
{
62+
var centreId = User.GetCentreId();
63+
if (!ModelState.IsValid)
64+
{
65+
var delegateEntity = userService.GetDelegateById(deactivateDelegateAccountViewModel.DelegateId)!;
66+
var userEntity = userService.GetUserById(delegateEntity.DelegateAccount.UserId);
67+
var adminAccount = userEntity!.GetCentreAccountSet(centreId)?.AdminAccount;
68+
var roles = GetRoles(adminAccount, userEntity);
69+
deactivateDelegateAccountViewModel.Roles = roles;
70+
return View(deactivateDelegateAccountViewModel);
71+
}
72+
73+
if (deactivateDelegateAccountViewModel.Deactivate == true )
74+
{
75+
userService.DeactivateDelegateUser(deactivateDelegateAccountViewModel.DelegateId);
76+
return RedirectToAction("Index", "ViewDelegate", new { deactivateDelegateAccountViewModel.DelegateId });
77+
}
78+
userService.DeactivateDelegateUser(deactivateDelegateAccountViewModel.DelegateId);
79+
userService.DeactivateAdminAccount(deactivateDelegateAccountViewModel.UserId, centreId.Value);
80+
return RedirectToAction("Index", "ViewDelegate", new { deactivateDelegateAccountViewModel.DelegateId });
81+
82+
}
83+
private List<string>? GetRoles(AdminAccount? adminAccount, UserEntity userEntity)
84+
{
85+
var roles = new List<string>();
86+
if (adminAccount != null)
87+
{
88+
var adminentity = new AdminEntity(adminAccount, userEntity.UserAccount, null);
89+
roles = FilterableTagHelper.GetCurrentTagsForAdmin(adminentity).Where(s => s.Hidden == false)
90+
.Select(d => d.DisplayText).ToList<string>();
91+
}
92+
return roles;
93+
}
94+
}
95+
}

DigitalLearningSolutions.Web/Services/UserService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ bool isWorkforceManager
194194
string search, int offset, int rows, int jobGroupId, string userStatus, string emailStatus, int userId, int failedLoginThreshold
195195
);
196196
void UpdateUserDetailsAccount(string firstName, string lastName, string primaryEmail, int jobGroupId, string? prnNumber, DateTime? emailVerified, int userId);
197+
void DeactivateAdminAccount(int userId, int centreId);
198+
int? CheckDelegateIsActive(int delegateId);
197199
}
198200

199201
public class UserService : IUserService
@@ -956,5 +958,13 @@ public void UpdateUserDetailsAccount(string firstName, string lastName, string p
956958
{
957959
userDataService.UpdateUserDetailsAccount(firstName, lastName, primaryEmail, jobGroupId, prnNumber, emailVerified, userId);
958960
}
961+
public void DeactivateAdminAccount(int userId, int centreId)
962+
{
963+
userDataService.DeactivateAdminAccount(userId, centreId);
964+
}
965+
public int? CheckDelegateIsActive(int delegateId)
966+
{
967+
return userDataService.CheckDelegateIsActive(delegateId);
968+
}
959969
}
960970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using FluentMigrator.Infrastructure;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.DataAnnotations;
4+
5+
namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.DeactivateDelegate
6+
{
7+
public class DeactivateDelegateAccountViewModel
8+
{
9+
public int DelegateId { get; set; }
10+
public int UserId { get; set; }
11+
public string Name { get; set; }
12+
public string Email { get; set; }
13+
public List<string> Roles { get; set; }
14+
[Required(ErrorMessage = "Please select an account you want to deactivate.")]
15+
public bool? Deactivate { get; set; }
16+
}
17+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
@using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.DeactivateDelegate
2+
@model DeactivateDelegateAccountViewModel
3+
4+
5+
@{
6+
var errorHasOccurred = !ViewData.ModelState.IsValid;
7+
ViewData["Title"] = errorHasOccurred ? "Error: Deactivate account" : "Deactivate account";
8+
}
9+
<div class="nhsuk-grid-row">
10+
<div class="nhsuk-grid-column-full">
11+
@if (errorHasOccurred)
12+
{
13+
<vc:error-summary order-of-property-names="@(new []{ nameof(Model.Name) })" />
14+
}
15+
16+
<h2 class="nhsuk-heading-l word-break">Deactivate account - @Model.Name (@Model.Email)</h2>
17+
<div class="nhsuk-grid-row">
18+
<div class="nhsuk-grid-column-full nhsuk-lede-text">
19+
@Model.Name has an active admin account at your centre with following admin roles:
20+
</div>
21+
</div>
22+
<div class="nhsuk-grid-row">
23+
<div class="nhsuk-grid-column-full nhsuk-lede-text">
24+
<ul>
25+
@foreach (var role in Model.Roles)
26+
{
27+
<li>@role</li>
28+
}
29+
</ul>
30+
</div>
31+
</div>
32+
33+
<form class="nhsuk-u-margin-bottom-3" method="post" novalidate asp-action="Index">
34+
<fieldset class="nhsuk-fieldset">
35+
<legend class="nhsuk-fieldset__legend nhsuk-fieldset__legend--l">
36+
<h2 class="nhsuk-fieldset__heading">
37+
Which accounts would you like deactivate?
38+
</h2>
39+
</legend>
40+
41+
<nhs-form-group nhs-validation-for="Deactivate">
42+
<div class="nhsuk-radios nhsuk-radios--inline">
43+
<div class="nhsuk-radios__item">
44+
<input class="nhsuk-radios__input" id="rb-accountonly" name="Deactivate" required="required" type="radio" value="true">
45+
<label class="nhsuk-label nhsuk-radios__label" for="rb-accountonly">
46+
Delegate account only
47+
</label>
48+
<div class="nhsuk-hint nhsuk-summary-list" id="cb-verify-item-hint">
49+
The user will still be able to login to your centre with the above admin roles
50+
</div>
51+
</div>
52+
<div class="nhsuk-radios__item">
53+
<input class="nhsuk-radios__input" id="rb-accountandadmin" name="Deactivate" required="required" type="radio" value="false">
54+
<label class="nhsuk-label nhsuk-radios__label" for="rb-accountandadmin">
55+
Delegate account and Administrators accounts
56+
</label>
57+
<div class="nhsuk-hint nhsuk-summary-list" id="cb-verify-item-hint">
58+
The user will no longer be able to login to your centre
59+
</div>
60+
</div>
61+
<span asp-validation-for="Deactivate" class="text-danger"></span>
62+
</div>
63+
</nhs-form-group>
64+
</fieldset>
65+
<button name="action" class="nhsuk-button delete-button view-delegate-button" value="save">Deactivate account</button>
66+
<input type="hidden" asp-for="DelegateId" />
67+
<input type="hidden" asp-for="Name" />
68+
<input type="hidden" asp-for="Email" />
69+
<input type="hidden" asp-for="Roles" />
70+
<input type="hidden" asp-for="UserId" />
71+
</form>
72+
<div class="nhsuk-back-link">
73+
<a class="nhsuk-back-link__link"
74+
asp-controller="ViewDelegate"
75+
asp-action="Index"
76+
asp-route-delegateId="@Model.DelegateId">
77+
<svg class="nhsuk-icon nhsuk-icon__chevron-left" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
78+
<path d="M13.41 12l5.3-5.29a1 1 0 1 0-1.42-1.42L12 10.59l-5.29-5.3a1 1 0 0 0-1.42 1.42l5.3 5.29-5.3 5.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l5.29-5.3 5.29 5.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"></path>
79+
</svg>
80+
Cancel
81+
</a>
82+
</div>
83+
</div>
84+
</div>

DigitalLearningSolutions.Web/Views/TrackingSystem/Delegates/ViewDelegate/Index.cshtml

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,48 +103,60 @@
103103
@if (Model.DelegateInfo.IsActive)
104104
{
105105
<a class="nhsuk-button view-delegate-button"
106-
role="button"
107-
asp-controller="EditDelegate"
108-
asp-action="Index"
109-
asp-route-delegateId="@Model.DelegateInfo.Id">
106+
role="button"
107+
asp-controller="EditDelegate"
108+
asp-action="Index"
109+
asp-route-delegateId="@Model.DelegateInfo.Id">
110110
Edit details
111111
</a>
112112
<a class="nhsuk-button nhsuk-button--secondary view-delegate-button"
113-
role="button"
114-
asp-controller="SetDelegatePassword"
115-
asp-action="Index"
116-
asp-route-delegateId="@Model.DelegateInfo.Id"
117-
asp-route-isFromViewDelegatePage="true">
113+
role="button"
114+
asp-controller="SetDelegatePassword"
115+
asp-action="Index"
116+
asp-route-delegateId="@Model.DelegateInfo.Id"
117+
asp-route-isFromViewDelegatePage="true">
118118
Set password
119119
</a>
120120
@if (User.HasCentreManagerPermissions() && !Model.DelegateInfo.IsAdmin
121121
&& !string.IsNullOrWhiteSpace(Model.DelegateInfo.Email) && !string.IsNullOrWhiteSpace(Model.DelegateInfo.Name))
122122
{
123123
<a class="nhsuk-button nhsuk-button--secondary view-delegate-button"
124-
role="button"
125-
asp-controller="PromoteToAdmin"
126-
asp-action="Index"
127-
asp-route-delegateId="@Model.DelegateInfo.Id">
124+
role="button"
125+
asp-controller="PromoteToAdmin"
126+
asp-action="Index"
127+
asp-route-delegateId="@Model.DelegateInfo.Id">
128128
Promote to admin
129129
</a>
130130
}
131131
if (Model.DelegateInfo.RegistrationConfirmationHash != null)
132132
{
133133
<form asp-action="DeleteAccount" asp-route-delegateId="@Model.DelegateInfo.Id">
134134
<button class="nhsuk-button delete-button view-delegate-button"
135-
type="submit">
135+
type="submit">
136136
Delete account
137137
</button>
138138
</form>
139139
}
140140
else
141141
{
142-
<form asp-action="DeactivateDelegate" asp-route-delegateId="@Model.DelegateInfo.Id">
143-
<button class="nhsuk-button delete-button view-delegate-button"
144-
type="submit">
142+
if (Model.DelegateInfo.IsAdmin)
143+
{
144+
<a class="nhsuk-button delete-button view-delegate-button" role="button"
145+
asp-controller="DeactivateDelegate"
146+
asp-action="Index"
147+
asp-route-delegateId="@Model.DelegateInfo.Id">
145148
Deactivate account
146-
</button>
147-
</form>
149+
</a>
150+
}
151+
else
152+
{
153+
<form asp-action="DeactivateDelegate" asp-route-delegateId="@Model.DelegateInfo.Id">
154+
<button class="nhsuk-button delete-button view-delegate-button"
155+
type="submit">
156+
Deactivate account
157+
</button>
158+
</form>
159+
}
148160
}
149161
}
150162
else
@@ -153,7 +165,7 @@
153165
{
154166
<form asp-action="DeleteAccount" asp-route-delegateId="@Model.DelegateInfo.Id">
155167
<button class="nhsuk-button delete-button view-delegate-button"
156-
type="submit">
168+
type="submit">
157169
Delete account
158170
</button>
159171
</form>
@@ -186,7 +198,7 @@
186198
if (delegateCourseInfoViewModel.ProgressId != null)
187199
{
188200
<partial name="_DelegateCourseInfoCard" model="delegateCourseInfoViewModel" />
189-
}
201+
}
190202
}
191203
@foreach (var delegateSelfAssessmentInfoViewModel in Model.SelfAssessments)
192204
{
@@ -199,12 +211,12 @@
199211
@if (Model.DelegateInfo.IsActive && !string.IsNullOrEmpty(Model.DelegateInfo.Email))
200212
{
201213
<a class="nhsuk-button nhsuk-button--secondary"
202-
role="button"
203-
asp-controller="Enrol"
204-
asp-action="StartEnrolProcess"
205-
asp-route-delegateId="@Model.DelegateInfo.Id"
206-
asp-route-delegateUserId="@Model.DelegateInfo.UserId"
207-
asp-route-delegateName="@Model.DelegateInfo.Name">
214+
role="button"
215+
asp-controller="Enrol"
216+
asp-action="StartEnrolProcess"
217+
asp-route-delegateId="@Model.DelegateInfo.Id"
218+
asp-route-delegateUserId="@Model.DelegateInfo.UserId"
219+
asp-route-delegateName="@Model.DelegateInfo.Name">
208220
Enrol on activity
209221
</a>
210222
}

0 commit comments

Comments
 (0)