Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit of the Contentful filter changes for the qualification list page. #234

Merged
merged 7 commits into from
Jul 9, 2024
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
@@ -0,0 +1,16 @@
namespace Dfe.EarlyYearsQualification.Content.Constants;

public static class AwardingOrganisations
{
public const string Edexcel = "Edexcel (now Pearson Education Ltd)";

public const string Pearson = "Pearson Education Ltd";

public const string Ncfe = "NCFE";

public const string Cache = "CACHE Council for Awards in Care Health and Education";

public const string Various = "Various Awarding Organisations";

public const string AllHigherEducation = "All Higher Education Institutes";
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="contentful.csharp" Version="7.6.0" />
<PackageReference Include="FuzzySharp" Version="2.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Dfe.EarlyYearsQualification.Content.Services;

public class ContentfulContentFilterService(
IContentfulClient contentfulClient,
IFuzzyAdapter fuzzyAdapter,
ILogger<ContentfulContentFilterService> logger)
: IContentFilterService
{
Expand Down Expand Up @@ -38,13 +39,15 @@ private static readonly ReadOnlyDictionary<string, int>
public QueryBuilder<Qualification> QueryBuilder { get; init; } = QueryBuilder<Qualification>.New;

public async Task<List<Qualification>> GetFilteredQualifications(int? level, int? startDateMonth,
sam-c-dfe marked this conversation as resolved.
Show resolved Hide resolved
int? startDateYear, string? awardingOrganisation)
int? startDateYear, string? awardingOrganisation,
string? qualificationName)
{
logger.LogInformation("Filtering options passed in - level: {Level}, startDateMonth: {StartDateMonth}, startDateYear: {StartDateYear}, awardingOrganisation: {AwardingOrganisation}",
logger.LogInformation("Filtering options passed in - level: {Level}, startDateMonth: {StartDateMonth}, startDateYear: {StartDateYear}, awardingOrganisation: {AwardingOrganisation}, qualificationName: {QualificationName}",
level,
startDateMonth,
startDateYear,
awardingOrganisation);
awardingOrganisation,
qualificationName);

// create query builder
var queryBuilder = QueryBuilder.ContentTypeIs(ContentTypes.Qualification);
Expand All @@ -56,7 +59,15 @@ public async Task<List<Qualification>> GetFilteredQualifications(int? level, int

if (!string.IsNullOrEmpty(awardingOrganisation))
{
queryBuilder = queryBuilder.FieldEquals("fields.awardingOrganisationTitle", awardingOrganisation);
var awardingOrganisations = new List<string>
{
"All Higher Education Institutes",
"Various Awarding Organisations"
};
awardingOrganisations.AddRange(IncludeLinkedOrganisations(awardingOrganisation, startDateMonth,
startDateYear));

queryBuilder = queryBuilder.FieldIncludes("fields.awardingOrganisationTitle", awardingOrganisations);
}

// get qualifications
Expand All @@ -71,19 +82,72 @@ public async Task<List<Qualification>> GetFilteredQualifications(int? level, int
return [];
}

if (!startDateMonth.HasValue || !startDateYear.HasValue) return qualifications.ToList();

// apply start date filtering
var results = FilterQualificationsByDate(startDateMonth.Value, startDateYear.Value, qualifications);
var filteredQualifications = FilterQualificationsByDate(startDateMonth, startDateYear, qualifications.ToList());

return results;
// Filter based on qualification name
filteredQualifications = FilterQualificationsByName(filteredQualifications, qualificationName);

return filteredQualifications;
}

private static List<string> IncludeLinkedOrganisations(string awardingOrganisation, int? startDateMonth,
int? startDateYear)
{
var result = new List<string>();

if (awardingOrganisation is AwardingOrganisations.Edexcel or AwardingOrganisations.Pearson)
{
result.AddRange(new List<string> { AwardingOrganisations.Edexcel, AwardingOrganisations.Pearson });
}
else if (awardingOrganisation is AwardingOrganisations.Ncfe or AwardingOrganisations.Cache
&& startDateMonth.HasValue && startDateYear.HasValue)
{
var cutOffDate = new DateOnly(2014, 9, 1);
var date = new DateOnly(startDateYear.Value, startDateMonth.Value, 1);
if (date >= cutOffDate)
{
result.AddRange(new List<string> { AwardingOrganisations.Ncfe, AwardingOrganisations.Cache });
}
else
{
result.Add(awardingOrganisation);
}
}
else
{
result.Add(awardingOrganisation);
}

return result;
}

private List<Qualification> FilterQualificationsByDate(int startDateMonth, int startDateYear,
ContentfulCollection<Qualification> qualifications)
private List<Qualification> FilterQualificationsByName(
List<Qualification> qualifications,
string? qualificationName)
{
if (string.IsNullOrEmpty(qualificationName)) return qualifications;

var matchedQualifications = new List<Qualification>();
foreach (var qualification in qualifications)
{
var weight = fuzzyAdapter.PartialRatio(qualificationName, qualification.QualificationName);
if (weight > 70)
{
matchedQualifications.Add(qualification);
}
}

return matchedQualifications;
}

private List<Qualification> FilterQualificationsByDate(int? startDateMonth, int? startDateYear,
List<Qualification> qualifications)
{
if (!startDateMonth.HasValue || !startDateYear.HasValue) return qualifications;

var results = new List<Qualification>();
var enteredStartDate = new DateOnly(startDateYear, startDateMonth, Day);
var enteredStartDate = new DateOnly(startDateYear.Value, startDateMonth.Value, Day);
foreach (var qualification in qualifications)
{
var qualificationStartDate = GetQualificationDate(qualification.FromWhichYear);
Expand Down
11 changes: 11 additions & 0 deletions src/Dfe.EarlyYearsQualification.Content/Services/FuzzyAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using FuzzySharp;

namespace Dfe.EarlyYearsQualification.Content.Services;

public class FuzzyAdapter : IFuzzyAdapter
{
public int PartialRatio(string input1, string input2)
{
return Fuzz.PartialRatio(input1, input2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace Dfe.EarlyYearsQualification.Content.Services;

public interface IContentFilterService
{
Task<List<Qualification>> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation);
Task<List<Qualification>> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation, string? qualificationName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Dfe.EarlyYearsQualification.Content.Services;

public interface IFuzzyAdapter
{
public int PartialRatio(string input1, string input2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Dfe.EarlyYearsQualification.Mock.Content;

public class MockContentfulFilterService : IContentFilterService
{
public Task<List<Qualification>> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation)
public Task<List<Qualification>> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation, string? qualificationName)
{
var qualifications =
new List<Qualification>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ public async Task<IActionResult> Get()

return View(model);
}

[HttpPost]
public IActionResult Refine(string refineSearch)
{
userJourneyCookieService.SetQualificationNameSearchCriteria(refineSearch);

return RedirectToAction("Get");
}

[HttpGet("qualification-details/{qualificationId}")]
public async Task<IActionResult> Index(string qualificationId)
Expand Down Expand Up @@ -69,9 +77,10 @@ private async Task<List<Qualification>> GetFilteredQualifications()
var level = userJourneyCookieService.GetLevelOfQualification();
var (startDateMonth, startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded();
var awardingOrganisation = userJourneyCookieService.GetAwardingOrganisation();
var searchCriteria = userJourneyCookieService.GetSearchCriteria();

return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear,
awardingOrganisation);
awardingOrganisation, searchCriteria);
}

private async Task<QualificationListModel> MapList(QualificationListPage content,
Expand All @@ -95,6 +104,7 @@ private async Task<QualificationListModel> MapList(QualificationListPage content
PostSearchCriteriaContent = await htmlRenderer.ToHtml(content.PostSearchCriteriaContent),
PostQualificationListContent = await htmlRenderer.ToHtml(content.PostQualificationListContent),
SearchCriteriaHeading = content.SearchCriteriaHeading,
SearchCriteria = userJourneyCookieService.GetSearchCriteria(),
Qualifications = basicQualificationsModels.OrderBy(x => x.QualificationName).ToList()
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private async Task<List<Qualification>> GetFilteredQualifications()
{
int? level = userJourneyCookieService.GetLevelOfQualification();
(int? startDateMonth, int? startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded();
return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear, null);
return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear, null, null);
}

private async Task<IActionResult> GetRadioView(string questionPageId, string actionName, string controllerName)
Expand Down Expand Up @@ -240,7 +240,7 @@ private static DropdownQuestionModel MapDropdownModel(DropdownQuestionModel mode
string controllerName)
{
var awardingOrganisationExclusions =
new[] { "All Higher Education Institutes", "Various Awarding Organisations" };
new[] { AwardingOrganisations.AllHigherEducation, AwardingOrganisations.Various };
var uniqueAwardingOrganisations = qualifications.Select(x => x.AwardingOrganisationTitle)
.Distinct()
.Where(x => !awardingOrganisationExclusions.Any(x.Contains))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class QualificationListModel
public FilterModel Filters { get; init; } = new();

public NavigationLink? BackButton { get; init; }

public string SingleQualificationFoundText { get; init; } = string.Empty;

public string MultipleQualificationsFoundText { get; init; } = string.Empty;
Expand All @@ -28,5 +28,7 @@ public class QualificationListModel

public string PostSearchCriteriaContent { get; init; } = string.Empty;

public string? SearchCriteria { get; init; } = string.Empty;

public List<BasicQualificationModel> Qualifications { get; init; } = [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ public class UserJourneyModel
public string WhenWasQualificationAwarded { get; set; } = string.Empty;
public string LevelOfQualification { get; set; } = string.Empty;
public string WhatIsTheAwardingOrganisation { get; set; } = string.Empty;

public string SearchCriteria { get; set; } = string.Empty;
}
3 changes: 2 additions & 1 deletion src/Dfe.EarlyYearsQualification.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
return factory.GetUrlHelper(actionContext!);
});

builder.Services.AddSingleton<IFuzzyAdapter, FuzzyAdapter>();

var accessIsChallenged = !builder.Configuration.GetValue<bool>("ServiceAccess:IsPublic");
// ...by default, challenge the user for the secret value unless that's explicitly turned off

Expand Down Expand Up @@ -105,7 +107,6 @@

await app.RunAsync();


[ExcludeFromCodeCoverage]
// ReSharper disable once UnusedType.Global
// ...declared partial so we can exclude it from code coverage calculations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ public interface IUserJourneyCookieService
public void SetWhenWasQualificationAwarded(string date);
public void SetLevelOfQualification(string level);
public void SetAwardingOrganisation(string awardingOrganisation);

public void SetQualificationNameSearchCriteria(string searchCriteria);
public UserJourneyModel GetUserJourneyModelFromCookie();
public void ResetUserJourneyCookie();

public string? GetWhereWasQualificationAwarded();
public (int? startMonth, int? startYear) GetWhenWasQualificationAwarded();
public int? GetLevelOfQualification();
public string? GetAwardingOrganisation();

public string? GetSearchCriteria();
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public void SetAwardingOrganisation(string awardingOrganisation)
SetJourneyCookie(model);
}

public void SetQualificationNameSearchCriteria(string searchCriteria)
{
var model = GetUserJourneyModelFromCookie();

model.SearchCriteria = searchCriteria;

SetJourneyCookie(model);
}

public UserJourneyModel GetUserJourneyModelFromCookie()
{
var cookie = context.HttpContext?.Request.Cookies[CookieKeyNames.UserJourneyKey];
Expand Down Expand Up @@ -132,6 +141,18 @@ public void ResetUserJourneyCookie()
return awardingOrganisation;
}

public string? GetSearchCriteria()
{
var cookie = GetUserJourneyModelFromCookie();
string? searchCriteria = null;
if (!string.IsNullOrEmpty(cookie.SearchCriteria))
{
searchCriteria = cookie.SearchCriteria;
}

return searchCriteria;
}

private void SetJourneyCookie(UserJourneyModel model)
{
var serializedCookie = JsonSerializer.Serialize(model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
</h3>
<div id="pre-search-content">@Html.Raw(Model.PreSearchBoxContent)</div>
<div class="govuk-form-group">
<input class="govuk-input govuk-!-width-three-quarters" id="refine-search" name="refine-search" aria-label="refine searYch box" type="text">
<button type="submit" class="govuk-button govuk-button--secondary" data-module="govuk-button">
@Model.SearchButtonText
</button>
@using (Html.BeginForm("Refine", "QualificationDetails", FormMethod.Post))
{
<input class="govuk-input govuk-!-width-three-quarters" id="refineSearch" name="refineSearch" aria-label="refine search box" type="text" value="@Model.SearchCriteria">
<button type="submit" class="govuk-button govuk-button--secondary" data-module="govuk-button">
@Model.SearchButtonText
</button>
}
</div>
@foreach (var qualification in Model.Qualifications)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const pages = [
"/questions/where-was-the-qualification-awarded",
"/questions/when-was-the-qualification-started",
"/questions/what-level-is-the-qualification",
"/questions/what-is-the-awarding-organisation",
"/qualifications",
"/qualifications/qualification-details/EYQ-240"
];
Expand All @@ -15,14 +16,15 @@ export const pagesWithForms = [
"/questions/where-was-the-qualification-awarded",
"/questions/when-was-the-qualification-started",
"/questions/what-level-is-the-qualification",
"/questions/what-is-the-awarding-organisation",
"/cookies",
"/qualifications",
];

export const pagesWithoutForms = [
"/",
"/accessibility-statement",
"/advice/qualification-outside-the-united-kingdom",
"/advice/level-2-qualifications-started-between-1-sept-2014-and-31-aug-2019",
"/qualifications",
"/qualifications/qualification-details/EYQ-240"
]
Loading
Loading