Skip to content

Commit 800094e

Browse files
Merge remote-tracking branch 'origin/DLS-Release-v1.2.3' into Develop/Features/TD-4624-Addregexvalidationofprofessionalregistrationnumberfieldthroughouttheapplication
2 parents 3d516df + 0cdf530 commit 800094e

File tree

22 files changed

+843
-385
lines changed

22 files changed

+843
-385
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace DigitalLearningSolutions.Data.Migrations
2+
{
3+
using FluentMigrator;
4+
5+
[Migration(202508190845)]
6+
public class AddSelfAssessmentProcessAgreed : Migration
7+
{
8+
public override void Up()
9+
{
10+
Alter.Table("CandidateAssessments").AddColumn("SelfAssessmentProcessAgreed").AsDateTime().Nullable();
11+
}
12+
13+
public override void Down()
14+
{
15+
Delete.Column("SelfAssessmentProcessAgreed").FromTable("CandidateAssessments");
16+
}
17+
}
18+
}

DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ int adminId
8080

8181
IEnumerable<GenericSelectList> GetAssessmentQuestions(int frameworkId, int adminId);
8282

83-
FrameworkDefaultQuestionUsage? GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId);
83+
FrameworkDefaultQuestionUsage GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId);
8484

8585
IEnumerable<GenericSelectList> GetAssessmentQuestionsForCompetency(int frameworkCompetencyId, int adminId);
8686

87-
AssessmentQuestionDetail? GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId);
87+
AssessmentQuestionDetail GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId);
8888

89-
LevelDescriptor? GetLevelDescriptorForAssessmentQuestionId(int assessmentQuestionId, int adminId, int level);
89+
LevelDescriptor GetLevelDescriptorForAssessmentQuestionId(int assessmentQuestionId, int adminId, int level);
9090

9191
IEnumerable<CompetencyResourceAssessmentQuestionParameter>
9292
GetSignpostingResourceParametersByFrameworkAndCompetencyId(int frameworkId, int competencyId);
@@ -122,7 +122,7 @@ bool zeroBased
122122
FrameworkReviewOutcomeNotification? GetFrameworkReviewNotification(int reviewId);
123123

124124
//INSERT DATA
125-
BrandedFramework? CreateFramework(DetailFramework detailFramework, int adminId);
125+
BrandedFramework CreateFramework(DetailFramework detailFramework, int adminId);
126126

127127
int InsertCompetencyGroup(string groupName, string? groupDescription, int adminId, int? frameworkId);
128128

@@ -367,7 +367,7 @@ public FrameworkDataService(IDbConnection connection, ILogger<FrameworkDataServi
367367
);
368368
}
369369

370-
public BaseFramework? GetBaseFrameworkByFrameworkId(int frameworkId, int adminId)
370+
public BaseFramework GetBaseFrameworkByFrameworkId(int frameworkId, int adminId)
371371
{
372372
return connection.QueryFirstOrDefault<BaseFramework>(
373373
$@"SELECT {BaseFrameworkFields}
@@ -377,7 +377,7 @@ public FrameworkDataService(IDbConnection connection, ILogger<FrameworkDataServi
377377
);
378378
}
379379

380-
public BrandedFramework? GetBrandedFrameworkByFrameworkId(int frameworkId, int adminId)
380+
public BrandedFramework GetBrandedFrameworkByFrameworkId(int frameworkId, int adminId)
381381
{
382382
return connection.QueryFirstOrDefault<BrandedFramework>(
383383
$@"SELECT {BaseFrameworkFields} {BrandedFrameworkFields}
@@ -484,7 +484,7 @@ public IEnumerable<FrameworkCompetency> GetAllCompetenciesForAdminId(string name
484484
);
485485
}
486486

487-
public BrandedFramework? CreateFramework(DetailFramework detailFramework, int adminId)
487+
public BrandedFramework CreateFramework(DetailFramework detailFramework, int adminId)
488488
{
489489
string frameworkName = detailFramework.FrameworkName;
490490
var description = detailFramework.Description;
@@ -532,7 +532,7 @@ public IEnumerable<FrameworkCompetency> GetAllCompetenciesForAdminId(string name
532532
return new BrandedFramework();
533533
}
534534

535-
return connection.QueryFirstOrDefault<BrandedFramework?>(
535+
return connection.QueryFirstOrDefault<BrandedFramework>(
536536
$@"SELECT {BaseFrameworkFields}
537537
FROM {FrameworkTables}
538538
WHERE FrameworkName = @frameworkName AND OwnerAdminID = @adminId",
@@ -867,7 +867,7 @@ public IEnumerable<FrameworkCompetencyGroup> GetFrameworkCompetencyGroups(int fr
867867
@"SELECT fcg.ID, fcg.CompetencyGroupID, cg.Name, cg.Description, fcg.Ordering, fc.ID, c.ID AS CompetencyID, c.Name, c.Description, fc.Ordering, COUNT(caq.AssessmentQuestionID) AS AssessmentQuestions
868868
,(SELECT COUNT(*) FROM CompetencyLearningResources clr WHERE clr.CompetencyID = c.ID AND clr.RemovedDate IS NULL) AS CompetencyLearningResourcesCount
869869
FROM FrameworkCompetencyGroups AS fcg INNER JOIN
870-
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID INNER JOIN
870+
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID LEFT OUTER JOIN
871871
FrameworkCompetencies AS fc ON fcg.ID = fc.FrameworkCompetencyGroupID LEFT OUTER JOIN
872872
Competencies AS c ON fc.CompetencyID = c.ID LEFT OUTER JOIN
873873
CompetencyAssessmentQuestions AS caq ON c.ID = caq.CompetencyID
@@ -1519,7 +1519,7 @@ FROM AssessmentQuestionInputTypes"
15191519
);
15201520
}
15211521

1522-
public FrameworkDefaultQuestionUsage? GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId)
1522+
public FrameworkDefaultQuestionUsage GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId)
15231523
{
15241524
return connection.QueryFirstOrDefault<FrameworkDefaultQuestionUsage>(
15251525
@"SELECT @assessmentQuestionId AS ID,
@@ -1620,7 +1620,7 @@ FROM CompetencyAssessmentQuestions INNER JOIN
16201620
}
16211621
}
16221622

1623-
public AssessmentQuestionDetail? GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId)
1623+
public AssessmentQuestionDetail GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId)
16241624
{
16251625
return connection.QueryFirstOrDefault<AssessmentQuestionDetail>(
16261626
$@"{AssessmentQuestionFields}{AssessmentQuestionDetailFields}
@@ -1630,7 +1630,7 @@ FROM CompetencyAssessmentQuestions INNER JOIN
16301630
);
16311631
}
16321632

1633-
public LevelDescriptor? GetLevelDescriptorForAssessmentQuestionId(
1633+
public LevelDescriptor GetLevelDescriptorForAssessmentQuestionId(
16341634
int assessmentQuestionId,
16351635
int adminId,
16361636
int level
@@ -2501,7 +2501,7 @@ FROM Flags AS f
25012501
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS FlagsCsv
25022502
FROM
25032503
Competencies AS c INNER JOIN
2504-
FrameworkCompetencies AS fc ON c.ID = fc.CompetencyID INNER JOIN
2504+
FrameworkCompetencies AS fc ON c.ID = fc.CompetencyID LEFT JOIN
25052505
FrameworkCompetencyGroups AS fcg ON fc.FrameworkCompetencyGroupID = fcg.ID LEFT JOIN
25062506
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID
25072507
WHERE (fc.FrameworkID = @frameworkId)

DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ CandidateAssessments AS CA LEFT OUTER JOIN
199199
SA.LinearNavigation,
200200
SA.UseDescriptionExpanders,
201201
SA.ManageOptionalCompetenciesPrompt,
202+
CAST(CASE WHEN CA.SelfAssessmentProcessAgreed IS NOT NULL THEN 1 ELSE 0 END AS BIT) AS SelfAssessmentProcessAgreed,
202203
CAST(CASE WHEN SA.SupervisorSelfAssessmentReview = 1 OR SA.SupervisorResultsReview = 1 THEN 1 ELSE 0 END AS BIT) AS IsSupervised,
203204
CASE
204205
WHEN (SELECT COUNT(*) FROM SelfAssessmentSupervisorRoles WHERE SelfAssessmentID = @selfAssessmentId AND AllowDelegateNomination = 1) > 0
@@ -247,7 +248,7 @@ GROUP BY
247248
CA.LaunchCount, CA.SubmittedDate, SA.LinearNavigation, SA.UseDescriptionExpanders,
248249
SA.ManageOptionalCompetenciesPrompt, SA.SupervisorSelfAssessmentReview, SA.SupervisorResultsReview,
249250
SA.ReviewerCommentsLabel,SA.EnforceRoleRequirementsForSignOff, SA.ManageSupervisorsDescription,CA.NonReportable,
250-
U.FirstName , U.LastName,SA.MinimumOptionalCompetencies",
251+
U.FirstName , U.LastName,SA.MinimumOptionalCompetencies, CA.SelfAssessmentProcessAgreed",
251252
new { delegateUserId, selfAssessmentId }
252253
);
253254
}
@@ -331,6 +332,22 @@ public void SetCompleteByDate(int selfAssessmentId, int delegateUserId, DateTime
331332
}
332333
}
333334

335+
public void MarkProgressAgreed(int selfAssessmentId, int delegateUserId)
336+
{
337+
var numberOfAffectedRows = connection.Execute(
338+
@"UPDATE CandidateAssessments SET SelfAssessmentProcessAgreed = GETDATE()
339+
WHERE SelfAssessmentID = @selfAssessmentId AND DelegateUserID = @delegateUserId",
340+
new { selfAssessmentId, delegateUserId }
341+
);
342+
if (numberOfAffectedRows < 1)
343+
{
344+
logger.LogWarning(
345+
"SelfAssessmentProcessAgreed not set as db update failed. " +
346+
$"Self assessment id: {selfAssessmentId}, Delegate User id: {delegateUserId}"
347+
);
348+
}
349+
}
350+
334351
public void SetUpdatedFlag(int selfAssessmentId, int delegateUserId, bool status)
335352
{
336353
var numberOfAffectedRows = connection.Execute(

DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ int competencyId
9191

9292
void SetBookmark(int selfAssessmentId, int delegateUserId, string bookmark);
9393

94+
void MarkProgressAgreed(int selfAssessmentId, int delegateUserId);
9495
IEnumerable<CandidateAssessment> GetCandidateAssessments(int delegateUserId, int selfAssessmentId);
9596

9697
// SelfAssessmentSupervisorDataService

DigitalLearningSolutions.Data/Models/SelfAssessments/CurrentSelfAssessment.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ public class CurrentSelfAssessment : SelfAssessment
2424
public int? DelegateUserId { get; set; }
2525
public string? DelegateName { get; set; }
2626
public string? EnrolledByFullName { get; set; }
27+
public bool SelfAssessmentProcessAgreed { get; set; }
2728
}
2829
}

DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/SelfAssessmentTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,5 +870,64 @@ public void SelfAssessmentOverview_Should_Return_View_With_Optional_Filter_Appli
870870

871871
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].Count().Should().Be(1);
872872
}
873+
874+
[Test]
875+
public void SelfAssessment_should_return_description_view_when_process_agreed_or_not_supervised()
876+
{
877+
// Given
878+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
879+
selfAssessment.IsSupervised = false; // or set SelfAssessmentProcessAgreed = true
880+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
881+
.Returns(selfAssessment);
882+
A.CallTo(() => selfAssessmentService.GetAllSupervisorsForSelfAssessmentId(SelfAssessmentId, DelegateUserId))
883+
.Returns(new List<SelfAssessmentSupervisor>());
884+
var expectedModel = new SelfAssessmentDescriptionViewModel(selfAssessment, new List<SelfAssessmentSupervisor>());
885+
886+
// When
887+
var result = controller.SelfAssessment(SelfAssessmentId);
888+
889+
// Then
890+
result.Should().BeViewResult()
891+
.WithViewName("SelfAssessments/SelfAssessmentDescription")
892+
.Model.Should().BeEquivalentTo(expectedModel);
893+
}
894+
895+
[Test]
896+
public void ProcessAgreed_should_return_agree_view_when_modelstate_invalid()
897+
{
898+
// Given
899+
var model = new SelfAssessmentProcessViewModel { SelfAssessmentID = SelfAssessmentId };
900+
controller.ModelState.AddModelError("Test", "Error");
901+
902+
// When
903+
var result = controller.ProcessAgreed(model);
904+
905+
// Then
906+
result.Should().BeViewResult()
907+
.WithViewName("SelfAssessments/AgreeSelfAssessmentProcess")
908+
.Model.Should().Be(model);
909+
}
910+
911+
[Test]
912+
public void ProcessAgreed_should_mark_progress_and_redirect_to_self_assessment()
913+
{
914+
// Given
915+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
916+
var model = new SelfAssessmentProcessViewModel { SelfAssessmentID = SelfAssessmentId };
917+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
918+
.Returns(selfAssessment);
919+
920+
// When
921+
var result = controller.ProcessAgreed(model);
922+
923+
// Then
924+
A.CallTo(() => selfAssessmentService.MarkProgressAgreed(SelfAssessmentId, DelegateUserId))
925+
.MustHaveHappenedOnceExactly();
926+
927+
result.Should().BeRedirectToActionResult()
928+
.WithActionName("SelfAssessment")
929+
.WithRouteValue("selfAssessmentId", SelfAssessmentId);
930+
}
931+
873932
}
874933
}

DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
using Microsoft.AspNetCore.Mvc.ViewEngines;
2929
using Microsoft.AspNetCore.Mvc.ViewFeatures;
3030
using System.IO;
31-
31+
[ServiceFilter(typeof(RequireProcessAgreementFilter))]
3232
public partial class LearningPortalController
3333
{
3434
private const string CookieName = "DLSSelfAssessmentService";
@@ -75,9 +75,56 @@ public IActionResult SelfAssessment(int selfAssessmentId)
7575
delegateUserId
7676
).ToList();
7777
var model = new SelfAssessmentDescriptionViewModel(selfAssessment, supervisors);
78+
7879
return View("SelfAssessments/SelfAssessmentDescription", model);
7980
}
8081

82+
[Route("/LearningPortal/SelfAssessment/{selfAssessmentId:int}/AgreeProcess")]
83+
public IActionResult AgreeSelfAssessmentProcess(int selfAssessmentId)
84+
{
85+
var delegateUserId = User.GetUserIdKnownNotNull();
86+
var selfAssessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId);
87+
88+
if (selfAssessment == null)
89+
{
90+
logger.LogWarning(
91+
$"Attempt to display self assessment process for user {delegateUserId} with no self assessment"
92+
);
93+
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
94+
}
95+
96+
var processmodel = new SelfAssessmentProcessViewModel()
97+
{
98+
SelfAssessmentID = selfAssessmentId,
99+
Vocabulary = selfAssessment.Vocabulary,
100+
VocabPlural = FrameworkVocabularyHelper.VocabularyPlural(selfAssessment.Vocabulary)
101+
};
102+
return View("SelfAssessments/AgreeSelfAssessmentProcess", processmodel);
103+
}
104+
105+
[HttpPost("/LearningPortal/SelfAssessment/{selfAssessmentId:int}/AgreeProcess")]
106+
public IActionResult ProcessAgreed(SelfAssessmentProcessViewModel model)
107+
{
108+
if (!ModelState.IsValid)
109+
{
110+
return View("SelfAssessments/AgreeSelfAssessmentProcess", model);
111+
}
112+
var delegateUserId = User.GetUserIdKnownNotNull();
113+
int selfAssessmentId = model.SelfAssessmentID;
114+
var selfAssessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId);
115+
if (selfAssessment == null)
116+
{
117+
logger.LogWarning(
118+
$"Attempt to display self assessment description for user {delegateUserId} with no self assessment"
119+
);
120+
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
121+
}
122+
123+
selfAssessmentService.MarkProgressAgreed(selfAssessmentId, delegateUserId);
124+
return RedirectToAction("SelfAssessment", new { selfAssessmentId });
125+
126+
}
127+
81128
[ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))]
82129
[Route("/LearningPortal/SelfAssessment/{selfAssessmentId:int}/{competencyNumber:int}")]
83130
public IActionResult SelfAssessmentCompetency(int selfAssessmentId, int competencyNumber)

DigitalLearningSolutions.Web/Controllers/SuperAdmin/Centres/CentresController.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System;
2222
using System.Collections.Generic;
2323
using System.Linq;
24-
using System.Text.RegularExpressions;
2524

2625
namespace DigitalLearningSolutions.Web.Controllers.SuperAdmin.Centres
2726
{
@@ -331,8 +330,7 @@ public IActionResult ManageCentreManager(EditCentreManagerDetailsViewModel editC
331330
{
332331
editCentreManagerDetailsViewModel.FirstName = editCentreManagerDetailsViewModel.FirstName == null ? string.Empty : editCentreManagerDetailsViewModel.FirstName.Trim();
333332
editCentreManagerDetailsViewModel.LastName = editCentreManagerDetailsViewModel.LastName == null ? string.Empty : editCentreManagerDetailsViewModel.LastName.Trim();
334-
editCentreManagerDetailsViewModel.Telephone = editCentreManagerDetailsViewModel.Telephone != null ? Regex.Replace(editCentreManagerDetailsViewModel.Telephone, @"\s+", "")
335-
: string.Empty; ;
333+
editCentreManagerDetailsViewModel.Telephone = editCentreManagerDetailsViewModel.Telephone?.Trim() ?? string.Empty;
336334
if (!ModelState.IsValid)
337335
{
338336
return View(editCentreManagerDetailsViewModel);

0 commit comments

Comments
 (0)