Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,16 @@ public void GetCompetencyResourceAssessmentQuestionParameters_returns_expected_r

testHelper.InsertLearningResourceReference(2, 2, adminId, "Resource 2");
testHelper.InsertCompetencyLearningResource(1, 1, 2, adminId);
testHelper.InsertCompetencyResourceAssessmentQuestionParameters(1, 1, true, 2, false);
testHelper.InsertCompetencyResourceAssessmentQuestionParameters(1, 1, true, 2, false, 1, 10);
var expectedItem = new CompetencyResourceAssessmentQuestionParameter
{
CompetencyLearningResourceId = 1,
AssessmentQuestionId = 1,
Essential = true,
RelevanceAssessmentQuestionId = 2,
CompareToRoleRequirements = false,
MinResultMatch = 1,
MaxResultMatch = 10,
};

// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Extensions\" />
<Folder Include="Services\TutorialContentDataServiceTests\" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace DigitalLearningSolutions.Data.Tests.Extensions
{
using System.Collections.Generic;
using DigitalLearningSolutions.Data.Extensions;
using FluentAssertions;
using NUnit.Framework;

public class EnumerableExtensionsTests
{
[Test]
public void WhereNotNull_filters_items_correctly()
{
// Given
var list = new List<string?> { "1", "2", null, "3", null, "4" };

// When
var result = list.WhereNotNull();

// Then
result.Should().BeEquivalentTo(new List<string> { "1", "2", "3", "4" });
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,20 @@ public void InsertCompetencyResourceAssessmentQuestionParameters(
int assessmentQuestionId,
bool essential,
int? relevanceQuestionId,
bool compareToRoleRequirements
bool compareToRoleRequirements,
int minMatchResult,
int maxMatchResult
)
{
connection.Execute(
@"INSERT INTO CompetencyResourceAssessmentQuestionParameters
(CompetencyLearningResourceId, AssessmentQuestionID, Essential, RelevanceAssessmentQuestionID, CompareToRoleRequirements, MinResultMatch, MaxResultMatch)
VALUES (@competencyLearningResourceId, @assessmentQuestionId, @essential, @relevanceQuestionId, @compareToRoleRequirements, 0, 0)",
new { competencyLearningResourceId, assessmentQuestionId, essential, relevanceQuestionId, compareToRoleRequirements }
VALUES (@competencyLearningResourceId, @assessmentQuestionId, @essential, @relevanceQuestionId, @compareToRoleRequirements, @minMatchResult, @maxMatchResult)",
new
{
competencyLearningResourceId, assessmentQuestionId, essential, relevanceQuestionId,
compareToRoleRequirements, minMatchResult, maxMatchResult,
}
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ public IEnumerable<CompetencyResourceAssessmentQuestionParameter>
AssessmentQuestionID,
Essential,
RelevanceAssessmentQuestionID,
CompareToRoleRequirements
CompareToRoleRequirements,
MinResultMatch,
MaxResultMatch
FROM CompetencyResourceAssessmentQuestionParameters
WHERE CompetencyLearningResourceId IN @competencyLearningResourceIds",
new { competencyLearningResourceIds }
Expand Down
13 changes: 13 additions & 0 deletions DigitalLearningSolutions.Data/Extensions/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace DigitalLearningSolutions.Data.Extensions
{
using System.Collections.Generic;
using System.Linq;

public static class EnumerableExtensions
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> enumerable) where T : class
{
return enumerable.Where(e => e != null).Select(e => e!);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ public class CompetencyResourceAssessmentQuestionParameter
public int? RelevanceAssessmentQuestionId { get; set; }

public bool CompareToRoleRequirements { get; set; }

public int MinResultMatch { get; set; }

public int MaxResultMatch { get; set; }
}
}
132 changes: 106 additions & 26 deletions DigitalLearningSolutions.Data/Services/RecommendedLearningService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using DigitalLearningSolutions.Data.ApiClients;
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService;
using DigitalLearningSolutions.Data.Extensions;
using DigitalLearningSolutions.Data.Models.External.LearningHubApiClient;
using DigitalLearningSolutions.Data.Models.LearningResources;
using DigitalLearningSolutions.Data.Models.SelfAssessments;
Expand Down Expand Up @@ -67,40 +68,119 @@ int delegateId
var delegateLearningLogItems = learningLogItemsDataService.GetLearningLogItems(delegateId);

var recommendedResources = resources.ResourceReferences.Select(
rr =>
{
var learningLogItemsForResource = delegateLearningLogItems.Where(
ll => ll.ArchivedDate == null && ll.LearningHubResourceReferenceId == rr.RefId
).ToList();
var incompleteLearningLogItem =
learningLogItemsForResource.SingleOrDefault(ll => ll.CompletedDate == null);
return new RecommendedResource(
resourceReferences[rr.RefId],
rr,
incompleteLearningLogItem,
learningLogItemsForResource.Any(ll => ll.CompletedDate != null),
CalculateRecommendedLearningScore(rr, competencyLearningResources, selfAssessmentId, delegateId)
);
}
rr => GetPopulatedRecommendedResource(
selfAssessmentId,
delegateId,
resourceReferences[rr.RefId],
delegateLearningLogItems,
rr,
competencyLearningResources
)
);

return recommendedResources;
return recommendedResources.WhereNotNull();
}

private decimal CalculateRecommendedLearningScore(
ResourceReferenceWithResourceDetails resource,
List<CompetencyLearningResource> competencyLearningResources,
private RecommendedResource? GetPopulatedRecommendedResource(
int selfAssessmentId,
int delegateId
int delegateId,
int learningHubResourceReferenceId,
IEnumerable<LearningLogItem> delegateLearningLogItems,
ResourceReferenceWithResourceDetails rr,
List<CompetencyLearningResource> competencyLearningResources
)
{
var learningLogItemsForResource = delegateLearningLogItems.Where(
ll => ll.ArchivedDate == null && ll.LearningHubResourceReferenceId == rr.RefId
).ToList();
var incompleteLearningLogItem =
learningLogItemsForResource.SingleOrDefault(ll => ll.CompletedDate == null);

var clrsForResource =
competencyLearningResources.Where(clr => clr.LearningHubResourceReferenceId == resource.RefId).ToList();
competencyLearningResources.Where(clr => clr.LearningHubResourceReferenceId == rr.RefId)
.ToList();

var competencyResourceAssessmentQuestionParameters =
competencyLearningResourcesDataService
.GetCompetencyResourceAssessmentQuestionParameters(clrsForResource.Select(clr => clr.Id)).ToList();
.GetCompetencyResourceAssessmentQuestionParameters(clrsForResource.Select(clr => clr.Id))
.ToList();

if (!AreDelegateAnswersWithinRangeToDisplayResource(
clrsForResource,
competencyResourceAssessmentQuestionParameters,
selfAssessmentId,
delegateId
))
{
return null;
}

return new RecommendedResource(
learningHubResourceReferenceId,
rr,
incompleteLearningLogItem,
learningLogItemsForResource.Any(ll => ll.CompletedDate != null),
CalculateRecommendedLearningScore(
rr,
clrsForResource,
competencyResourceAssessmentQuestionParameters,
selfAssessmentId,
delegateId
)
);
}

private bool AreDelegateAnswersWithinRangeToDisplayResource(
List<CompetencyLearningResource> clrsForResource,
List<CompetencyResourceAssessmentQuestionParameter> competencyResourceAssessmentQuestionParameters,
int selfAssessmentId,
int delegateId
)
{
foreach (var competencyLearningResource in clrsForResource)
{
var delegateResults = selfAssessmentDataService
.GetSelfAssessmentResultsForDelegateSelfAssessmentCompetency(
delegateId,
selfAssessmentId,
competencyLearningResource.CompetencyId
).ToList();

var competencyResourceAssessmentQuestionParametersForClr =
competencyResourceAssessmentQuestionParameters.SingleOrDefault(
qp => qp.CompetencyLearningResourceId == competencyLearningResource.Id
);

if (competencyResourceAssessmentQuestionParametersForClr == null)
{
return true;
}

var latestConfidenceResult = delegateResults
.Where(
dr => dr.AssessmentQuestionId ==
competencyResourceAssessmentQuestionParametersForClr.AssessmentQuestionId
)
.OrderByDescending(dr => dr.DateTime).FirstOrDefault();

if (competencyResourceAssessmentQuestionParametersForClr.MinResultMatch <= latestConfidenceResult?.Result &&
latestConfidenceResult.Result <= competencyResourceAssessmentQuestionParametersForClr.MaxResultMatch)
{
return true;
}
}

return false;
}

private decimal CalculateRecommendedLearningScore(
ResourceReferenceWithResourceDetails resource,
List<CompetencyLearningResource> clrsForResource,
List<CompetencyResourceAssessmentQuestionParameter> competencyResourceAssessmentQuestionParameters,
int selfAssessmentId,
int delegateId
)
{
var essentialnessValue = CalculateEssentialnessValue(competencyResourceAssessmentQuestionParameters);

var learningHubRating = resource.Rating;
Expand Down Expand Up @@ -134,17 +214,17 @@ int delegateId

foreach (var competencyLearningResource in competencyLearningResources)
{
var competencyResourceAssessmentQuestionParameterForClr =
var competencyResourceAssessmentQuestionParametersForClr =
competencyResourceAssessmentQuestionParameters.SingleOrDefault(
c => c.CompetencyLearningResourceId == competencyLearningResource.Id
);

if (competencyResourceAssessmentQuestionParameterForClr == null)
if (competencyResourceAssessmentQuestionParametersForClr == null)
{
break;
}

if (competencyResourceAssessmentQuestionParameterForClr.CompareToRoleRequirements)
if (competencyResourceAssessmentQuestionParametersForClr.CompareToRoleRequirements)
{
requirementAdjusters.Add(
CalculateRoleRequirementValue(competencyLearningResource.CompetencyId, selfAssessmentId)
Expand All @@ -158,7 +238,7 @@ int delegateId
.CompetencyId,
selfAssessmentId,
delegateId,
competencyResourceAssessmentQuestionParameterForClr
competencyResourceAssessmentQuestionParametersForClr
)
);
}
Expand Down