Skip to content

Commit 5f706f6

Browse files
committed
Merge branch 'DLS-Release-v1.2.4' into DLS-Release-v1.3.0
2 parents 25fa3e0 + 58002c9 commit 5f706f6

File tree

8 files changed

+150
-91
lines changed

8 files changed

+150
-91
lines changed

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",
@@ -873,7 +873,7 @@ FROM SelfAssessmentStructure
873873
(SELECT COUNT(*) FROM CompetencyAssessmentQuestions caq WHERE caq.CompetencyID = c.ID) AS AssessmentQuestions
874874
,(SELECT COUNT(*) FROM CompetencyLearningResources clr WHERE clr.CompetencyID = c.ID AND clr.RemovedDate IS NULL) AS CompetencyLearningResourcesCount
875875
FROM FrameworkCompetencyGroups AS fcg INNER JOIN
876-
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID INNER JOIN
876+
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID LEFT OUTER JOIN
877877
FrameworkCompetencies AS fc ON fcg.ID = fc.FrameworkCompetencyGroupID LEFT OUTER JOIN
878878
Competencies AS c ON fc.CompetencyID = c.ID
879879
WHERE (fcg.FrameworkID = @frameworkId) {assessmentFilter}
@@ -1531,7 +1531,7 @@ FROM AssessmentQuestionInputTypes"
15311531
);
15321532
}
15331533

1534-
public FrameworkDefaultQuestionUsage? GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId)
1534+
public FrameworkDefaultQuestionUsage GetFrameworkDefaultQuestionUsage(int frameworkId, int assessmentQuestionId)
15351535
{
15361536
return connection.QueryFirstOrDefault<FrameworkDefaultQuestionUsage>(
15371537
@"SELECT @assessmentQuestionId AS ID,
@@ -1632,7 +1632,7 @@ FROM CompetencyAssessmentQuestions INNER JOIN
16321632
}
16331633
}
16341634

1635-
public AssessmentQuestionDetail? GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId)
1635+
public AssessmentQuestionDetail GetAssessmentQuestionDetailById(int assessmentQuestionId, int adminId)
16361636
{
16371637
return connection.QueryFirstOrDefault<AssessmentQuestionDetail>(
16381638
$@"{AssessmentQuestionFields}{AssessmentQuestionDetailFields}
@@ -1642,7 +1642,7 @@ FROM CompetencyAssessmentQuestions INNER JOIN
16421642
);
16431643
}
16441644

1645-
public LevelDescriptor? GetLevelDescriptorForAssessmentQuestionId(
1645+
public LevelDescriptor GetLevelDescriptorForAssessmentQuestionId(
16461646
int assessmentQuestionId,
16471647
int adminId,
16481648
int level
@@ -2516,7 +2516,7 @@ FROM Flags AS f
25162516
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS FlagsCsv
25172517
FROM
25182518
Competencies AS c INNER JOIN
2519-
FrameworkCompetencies AS fc ON c.ID = fc.CompetencyID INNER JOIN
2519+
FrameworkCompetencies AS fc ON c.ID = fc.CompetencyID LEFT JOIN
25202520
FrameworkCompetencyGroups AS fcg ON fc.FrameworkCompetencyGroupID = fcg.ID LEFT JOIN
25212521
CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID
25222522
WHERE (fc.FrameworkID = @frameworkId)

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

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -871,28 +871,6 @@ public void SelfAssessmentOverview_Should_Return_View_With_Optional_Filter_Appli
871871
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].Count().Should().Be(1);
872872
}
873873

874-
[Test]
875-
public void SelfAssessment_should_return_process_agreement_view_when_not_agreed_and_supervised()
876-
{
877-
// Given
878-
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
879-
selfAssessment.IsSupervised = true;
880-
selfAssessment.SelfAssessmentProcessAgreed = false;
881-
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
882-
.Returns(selfAssessment);
883-
A.CallTo(() => selfAssessmentService.GetAllSupervisorsForSelfAssessmentId(SelfAssessmentId, DelegateUserId))
884-
.Returns(new List<SelfAssessmentSupervisor>());
885-
886-
// When
887-
var result = controller.SelfAssessment(SelfAssessmentId);
888-
889-
// Then
890-
result.Should().BeViewResult()
891-
.WithViewName("SelfAssessments/AgreeSelfAssessmentProcess")
892-
.Model.Should().BeOfType<SelfAssessmentProcessViewModel>()
893-
.Which.SelfAssessmentID.Should().Be(SelfAssessmentId);
894-
}
895-
896874
[Test]
897875
public void SelfAssessment_should_return_description_view_when_process_agreed_or_not_supervised()
898876
{
@@ -931,25 +909,25 @@ public void ProcessAgreed_should_return_agree_view_when_modelstate_invalid()
931909
}
932910

933911
[Test]
934-
public void ProcessAgreed_should_mark_progress_and_return_description_view()
912+
public void ProcessAgreed_should_mark_progress_and_redirect_to_self_assessment()
935913
{
936914
// Given
937915
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
938-
var supervisors = new List<SelfAssessmentSupervisor>();
939916
var model = new SelfAssessmentProcessViewModel { SelfAssessmentID = SelfAssessmentId };
940917
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
941918
.Returns(selfAssessment);
942-
A.CallTo(() => selfAssessmentService.GetAllSupervisorsForSelfAssessmentId(SelfAssessmentId, DelegateUserId))
943-
.Returns(supervisors);
944919

945920
// When
946921
var result = controller.ProcessAgreed(model);
947922

948923
// Then
949-
A.CallTo(() => selfAssessmentService.MarkProgressAgreed(SelfAssessmentId, DelegateUserId)).MustHaveHappened();
950-
result.Should().BeViewResult()
951-
.WithViewName("SelfAssessments/SelfAssessmentDescription")
952-
.Model.Should().BeEquivalentTo(new SelfAssessmentDescriptionViewModel(selfAssessment, supervisors));
924+
A.CallTo(() => selfAssessmentService.MarkProgressAgreed(SelfAssessmentId, DelegateUserId))
925+
.MustHaveHappenedOnceExactly();
926+
927+
result.Should().BeRedirectToActionResult()
928+
.WithActionName("SelfAssessment")
929+
.WithRouteValue("selfAssessmentId", SelfAssessmentId);
953930
}
931+
954932
}
955933
}

DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs

Lines changed: 27 additions & 19 deletions
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";
@@ -68,17 +68,6 @@ public IActionResult SelfAssessment(int selfAssessmentId)
6868
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
6969
}
7070

71-
if (!selfAssessment.SelfAssessmentProcessAgreed && selfAssessment.IsSupervised)
72-
{
73-
var processmodel = new SelfAssessmentProcessViewModel()
74-
{
75-
SelfAssessmentID = selfAssessmentId,
76-
Vocabulary = selfAssessment.Vocabulary,
77-
VocabPlural = FrameworkVocabularyHelper.VocabularyPlural(selfAssessment.Vocabulary)
78-
};
79-
return View("SelfAssessments/AgreeSelfAssessmentProcess", processmodel);
80-
}
81-
8271
selfAssessmentService.IncrementLaunchCount(selfAssessmentId, delegateUserId);
8372
selfAssessmentService.UpdateLastAccessed(selfAssessmentId, delegateUserId);
8473
var supervisors = selfAssessmentService.GetAllSupervisorsForSelfAssessmentId(
@@ -90,7 +79,30 @@ public IActionResult SelfAssessment(int selfAssessmentId)
9079
return View("SelfAssessments/SelfAssessmentDescription", model);
9180
}
9281

93-
[HttpPost]
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")]
94106
public IActionResult ProcessAgreed(SelfAssessmentProcessViewModel model)
95107
{
96108
if (!ModelState.IsValid)
@@ -107,13 +119,9 @@ public IActionResult ProcessAgreed(SelfAssessmentProcessViewModel model)
107119
);
108120
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
109121
}
110-
var supervisors = selfAssessmentService.GetAllSupervisorsForSelfAssessmentId(
111-
selfAssessmentId,
112-
delegateUserId
113-
).ToList();
114-
var selfAssessmentDescriptionViewModel = new SelfAssessmentDescriptionViewModel(selfAssessment, supervisors);
122+
115123
selfAssessmentService.MarkProgressAgreed(selfAssessmentId, delegateUserId);
116-
return View("SelfAssessments/SelfAssessmentDescription", selfAssessmentDescriptionViewModel);
124+
return RedirectToAction("SelfAssessment", new { selfAssessmentId });
117125

118126
}
119127

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
namespace DigitalLearningSolutions.Web.ServiceFilter
2+
{
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.AspNetCore.Mvc.Filters;
5+
using DigitalLearningSolutions.Web.Services;
6+
using DigitalLearningSolutions.Web.Helpers;
7+
using Microsoft.Extensions.Logging;
8+
9+
public class RequireProcessAgreementFilter : IActionFilter
10+
{
11+
private readonly ISelfAssessmentService selfAssessmentService;
12+
private readonly ILogger<RequireProcessAgreementFilter> logger;
13+
14+
public RequireProcessAgreementFilter(
15+
ISelfAssessmentService selfAssessmentService,
16+
ILogger<RequireProcessAgreementFilter> logger
17+
)
18+
{
19+
this.selfAssessmentService = selfAssessmentService;
20+
this.logger = logger;
21+
}
22+
23+
public void OnActionExecuted(ActionExecutedContext context) { }
24+
25+
public void OnActionExecuting(ActionExecutingContext context)
26+
{
27+
if (context.HttpContext.Request.Path.ToString().Contains("/LearningPortal/SelfAssessment/"))
28+
{
29+
if (!(context.Controller is Controller controller))
30+
{
31+
return;
32+
}
33+
34+
if (!context.ActionArguments.ContainsKey("selfAssessmentId"))
35+
{
36+
return;
37+
}
38+
39+
var selfAssessmentId = int.Parse(context.ActionArguments["selfAssessmentId"].ToString()!);
40+
var delegateUserId = controller.User.GetUserIdKnownNotNull();
41+
42+
var selfAssessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId);
43+
44+
if (selfAssessment == null)
45+
{
46+
logger.LogWarning(
47+
$"Attempt to access self assessment {selfAssessmentId} by user {delegateUserId}, but no such assessment found"
48+
);
49+
context.Result = new RedirectToActionResult("StatusCode", "LearningSolutions", new { code = 403 });
50+
return;
51+
}
52+
53+
var actionName = context.RouteData.Values["action"]?.ToString();
54+
if (actionName == "AgreeSelfAssessmentProcess" || actionName == "ProcessAgreed")
55+
{
56+
return;
57+
}
58+
59+
if (!selfAssessment.SelfAssessmentProcessAgreed && selfAssessment.IsSupervised)
60+
{
61+
logger.LogInformation(
62+
$"Redirecting user {delegateUserId} to agree process page for self assessment {selfAssessmentId}"
63+
);
64+
65+
context.Result = new RedirectToActionResult(
66+
"AgreeSelfAssessmentProcess",
67+
"LearningPortal",
68+
new { selfAssessmentId }
69+
);
70+
}
71+
}
72+
}
73+
}
74+
}

DigitalLearningSolutions.Web/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ private static void RegisterWebServiceFilters(IServiceCollection services)
582582
services.AddScoped<VerifyUserHasVerifiedPrimaryEmail>();
583583
services.AddScoped<VerifyAdminAndDelegateUserCentre>();
584584
services.AddScoped<IsCentreAuthorizedSelfAssessment>();
585+
services.AddScoped<RequireProcessAgreementFilter>();
585586
services.AddScoped<VerifyAdminUserCanAccessSelfAssessment>();
586587
}
587588

0 commit comments

Comments
 (0)