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

Feature/ilr submission #1969

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e87ed4b
starter for 10 - no change of circumstance
rgparkins Feb 5, 2025
be5801e
Rate limiting implemented
rgparkins Feb 5, 2025
49b5354
API Key implemented
rgparkins Feb 5, 2025
72a0a35
remove the paged response as this is only for inner API
rgparkins Feb 5, 2025
a3fe5d2
description updates for put
rgparkins Feb 5, 2025
512e9a0
pages leaners per provider upport
rgparkins Feb 5, 2025
51c4072
rename directory to LearnerData
rgparkins Feb 5, 2025
bc77722
rename
rgparkins Feb 5, 2025
9883e7a
approved candidate support
rgparkins Feb 5, 2025
844ff00
Added a bad request and update descriptions for endpoints
rgparkins Feb 5, 2025
94d1e4a
rename candidae
rgparkins Feb 6, 2025
537ff84
rename candidate
rgparkins Feb 6, 2025
06fbfed
rename candidate
rgparkins Feb 6, 2025
5761ced
rename prior learning percent
rgparkins Feb 6, 2025
0bda689
add general endpoints plus agreementId on learner
rgparkins Feb 11, 2025
3ada273
add general endpoints plus agreementId on learner
rgparkins Feb 12, 2025
54a9702
add general endpoints plus agreementId on learner
rgparkins Feb 12, 2025
2762320
add general endpoints plus agreementId on learner
rgparkins Feb 12, 2025
8281ec5
remove POST and use PUT
rgparkins Feb 13, 2025
eaa3770
remove 404
rgparkins Feb 13, 2025
65a5689
Added the request bodygit add .git add .
rgparkins Feb 13, 2025
28c9f36
new paged link headers. Now accepting request in instead of creating
rgparkins Feb 13, 2025
55007a4
Endpoint for canned learner data for DC (SLD)
rgparkins Feb 20, 2025
8e944d9
Remove the resource Loader
rgparkins Feb 21, 2025
33754a0
make changes
cofaulco Feb 21, 2025
4810a6f
fix post merge
cofaulco Feb 21, 2025
7a42023
Merge pull request #1974 from SkillsFundingAgency/CF-ILR-updates
cofaulco Feb 21, 2025
6f13500
UKPRN and ULN cannot be primary key
rgparkins Feb 24, 2025
f5bbef0
UKPRN and ULN cannot be primary key
rgparkins Feb 24, 2025
e2b2181
UKPRN and ULN cannot be primary key
rgparkins Feb 24, 2025
0dae4af
Removed the GET call as not needed
rgparkins Feb 24, 2025
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,62 @@
using Microsoft.AspNetCore.Mvc;
using SFA.DAS.Earnings.Api.Learnerdata;

namespace SFA.DAS.Earnings.Api.Controllers;

[ApiController]
[Route("leanerdata")]
public class LearnerDataController : Controller
{
private readonly ILearnerDataSearchService _service;

public LearnerDataController(ILearnerDataSearchService service)
{
_service = service;
}

[HttpGet]
[Route("/providers/{ukprn}/academicyears/{academicyear}/apprenticeships")]
public IActionResult Search(uint ukprn, uint academicyear, [FromQuery] uint page, [FromQuery] uint pageSize)
{
if (pageSize < 1 || pageSize > 100)
{
return BadRequest("Page size must be between 1 and 100");
}

if (page < 1)
{
return BadRequest("Invalid page requested");
}

var result = _service.Search(ukprn, academicyear, page==0?1:page, pageSize==0?20:pageSize);

// Add Link headers for pagination
var baseUrl = $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Request.Path}";
var nextPage = page * pageSize < result.TotalRecords ? page + 1 : page;
var prevPage = page > 1 ? page - 1 : 1;

var header = "";

if (prevPage != page)
{
header += $"<{baseUrl}?page={prevPage}&pageSize={pageSize}>; rel=\"prev\", ";
}

if (nextPage != page)
{
if (header.Length > 0)
{
header += ", ";
}

header += $"<{baseUrl}?page={nextPage}&pageSize={pageSize}>; rel=\"next\"";
}

if (header.Length > 0)
{
Response.Headers["Link"] = header;
}

return Ok(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace SFA.DAS.Earnings.Api.Learnerdata;

public class Apprenticeship {
public uint Uln { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace SFA.DAS.Earnings.Api.Learnerdata;

public interface ILearnerDataSearchService
{
PagedResult Search(uint ukprn, uint academicYear, uint page, uint pageSize);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SFA.DAS.Earnings.Api.Controllers;

namespace SFA.DAS.Earnings.Api.Learnerdata;

public interface ILearnerDataStore
{
List<Apprenticeship> Search(uint ukprn, uint academicYear, uint page, uint pageSize);
int Count(uint ukprn, uint academicYear);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace SFA.DAS.Earnings.Api.Learnerdata;

public class LearnerDataSearchService : ILearnerDataSearchService
{
private readonly ILearnerDataStore _datastore;

public LearnerDataSearchService(ILearnerDataStore datastore)
{
_datastore = datastore;
}

public PagedResult Search(uint ukprn, uint academicYear, uint page, uint pageSize)
{
var results = _datastore.Search(ukprn, academicYear, page, pageSize);

var totalRecords = _datastore.Count(ukprn, academicYear);

return new PagedResult
{
Page = page,
PageSize = pageSize,
TotalRecords = (uint)totalRecords,
Apprenticeships = results,
TotalPages = (uint)Math.Ceiling((double)totalRecords / pageSize)
};
}

}
61 changes: 61 additions & 0 deletions src/Earnings/SFA.DAS.Earnings.Api/Learnerdata/LearnerDataStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Reflection;
using SFA.DAS.Earnings.Api.Controllers;

namespace SFA.DAS.Earnings.Api.Learnerdata;

public class LearnerDataStore : ILearnerDataStore
{
private readonly List<Tuple<uint, uint, uint, uint>> _data = new();

public LearnerDataStore(string resourcePath)
{
var loader = new ResourceLoader();

try
{
using (var stream = Assembly.GetAssembly(typeof(LearnerDataStore)).GetManifestResourceStream(resourcePath))
{
using (StreamReader reader = new StreamReader(stream))
{
string line;
uint count = 0;

while ((line = reader.ReadLine()) != null)
{
var entries = line.Split(',');
_data.Add(new Tuple<uint, uint, uint, uint>(++count,uint.Parse(entries[0]), uint.Parse(entries[1]), uint.Parse(entries[2])));
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading resource: {ex.Message}");
}
}
public LearnerDataStore(List<Tuple<uint, uint, uint>> data)
{
for (int c = 0; c < data.Count; c++)
{
_data.Add(new Tuple<uint, uint, uint, uint>((uint)c, data[c].Item1, data[c].Item2, data[c].Item3));
}
}

public List<Apprenticeship> Search(uint ukprn, uint academicYear, uint page, uint pageSize)
{
return _data
.Where(s => s.Item2 == ukprn & s.Item3 == academicYear)
.OrderBy(l => l.Item1)
.Skip((int)(pageSize * (page-1)))
.Take((int)pageSize)
.Select(s => new Apprenticeship
{
Uln = s.Item4
}).ToList();
}

public int Count(uint ukprn, uint academicYear)
{
return _data.Count(s => s.Item3 == academicYear & s.Item2 == ukprn);
}
}
16 changes: 16 additions & 0 deletions src/Earnings/SFA.DAS.Earnings.Api/Learnerdata/PagedResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using SFA.DAS.Earnings.Api.Controllers;

namespace SFA.DAS.Earnings.Api.Learnerdata;

public class PagedResult {
public IList<Apprenticeship> Apprenticeships { get; set; }
public uint TotalRecords { get; set; }
public uint Page { get; set; }
public uint PageSize { get; set; }
public uint TotalPages { get; set; }

public PagedResult()
{
Apprenticeships = new List<Apprenticeship>();
}
}
26 changes: 26 additions & 0 deletions src/Earnings/SFA.DAS.Earnings.Api/Learnerdata/ResourceLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Reflection;

namespace SFA.DAS.Earnings.Api.Learnerdata;

public class ResourceLoader
{
public string LoadEmbeddedResource(string resourcePath)
{
// Get the current assembly
var assembly = Assembly.GetExecutingAssembly();

// Ensure the resource exists in the assembly
using (Stream stream = assembly.GetManifestResourceStream(resourcePath))
{
if (stream == null)
{
throw new FileNotFoundException("Resource not found.", resourcePath);
}

using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
}
4 changes: 4 additions & 0 deletions src/Earnings/SFA.DAS.Earnings.Api/SFA.DAS.Earnings.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@
<ProjectReference Include="..\SFA.DAS.Earnings\SFA.DAS.Earnings.csproj" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="cannedLearnerData.csv" />
</ItemGroup>

</Project>
6 changes: 5 additions & 1 deletion src/Earnings/SFA.DAS.Earnings.Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using SFA.DAS.Api.Common.AppStart;
using SFA.DAS.Api.Common.Configuration;
using SFA.DAS.Earnings.Api.AppStart;
using SFA.DAS.Earnings.Api.Controllers;
using SFA.DAS.Earnings.Api.Learnerdata;
using SFA.DAS.SharedOuterApi.AppStart;
using SFA.DAS.SharedOuterApi.Infrastructure.HealthCheck;

Expand All @@ -30,7 +32,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddSingleton(_env);

services.AddConfigurationOptions(_configuration);

if (!_configuration.IsLocalOrDev())
{
var azureAdConfiguration = _configuration
Expand All @@ -56,6 +58,8 @@ public void ConfigureServices(IServiceCollection services)
}
});

services.AddSingleton<ILearnerDataSearchService>(new LearnerDataSearchService(new LearnerDataStore("SFA.DAS.Earnings.Api.cannedLearnerData.csv")));

services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

Expand Down
Loading