- Remove unused GetRepoLanguagesAsync method from GitHubClient - Remove unused IsFakeAccreditor and FakeAccreditors from DiplomaMills - Remove unused CompanyVerificationFlagPenalty constant from ProcessCVCheckJob - Remove unused SkillVerification properties (TotalLinesOfCode, FirstUsed, LastUsed) - Remove unused CompanyMatchRequest record from SemanticMatchResult - Add JsonDefaults.ApiClient and consolidate duplicate JsonSerializerOptions across API clients - Remove ApiTester tool containing hardcoded API credentials (security fix) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
211 lines
6.0 KiB
C#
211 lines
6.0 KiB
C#
using System.Net.Http.Json;
|
|
using System.Text.Json.Serialization;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using RealCV.Application.Helpers;
|
|
|
|
namespace RealCV.Infrastructure.Clients;
|
|
|
|
public sealed class FcaRegisterClient
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly ILogger<FcaRegisterClient> _logger;
|
|
private readonly string _apiKey;
|
|
|
|
public FcaRegisterClient(
|
|
HttpClient httpClient,
|
|
IOptions<FcaOptions> options,
|
|
ILogger<FcaRegisterClient> logger)
|
|
{
|
|
_httpClient = httpClient;
|
|
_logger = logger;
|
|
_apiKey = options.Value.ApiKey;
|
|
|
|
_httpClient.BaseAddress = new Uri("https://register.fca.org.uk/services/V0.1/");
|
|
_httpClient.DefaultRequestHeaders.Add("X-Auth-Email", options.Value.Email);
|
|
_httpClient.DefaultRequestHeaders.Add("X-Auth-Key", _apiKey);
|
|
}
|
|
|
|
public async Task<FcaIndividualResponse?> SearchIndividualsAsync(string name, int page = 1)
|
|
{
|
|
try
|
|
{
|
|
var encodedName = Uri.EscapeDataString(name);
|
|
var url = $"Individuals?q={encodedName}&page={page}";
|
|
|
|
_logger.LogDebug("Searching FCA for individual: {Name}", name);
|
|
|
|
var response = await _httpClient.GetAsync(url);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
_logger.LogWarning("FCA API returned {StatusCode} for search: {Name}",
|
|
response.StatusCode, name);
|
|
return null;
|
|
}
|
|
|
|
return await response.Content.ReadFromJsonAsync<FcaIndividualResponse>(JsonDefaults.ApiClient);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error searching FCA for individual: {Name}", name);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<FcaIndividualDetails?> GetIndividualAsync(string individualReferenceNumber)
|
|
{
|
|
try
|
|
{
|
|
var url = $"Individuals/{individualReferenceNumber}";
|
|
|
|
_logger.LogDebug("Getting FCA individual: {IRN}", individualReferenceNumber);
|
|
|
|
var response = await _httpClient.GetAsync(url);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
_logger.LogWarning("FCA API returned {StatusCode} for IRN: {IRN}",
|
|
response.StatusCode, individualReferenceNumber);
|
|
return null;
|
|
}
|
|
|
|
var wrapper = await response.Content.ReadFromJsonAsync<FcaIndividualDetailsWrapper>(JsonDefaults.ApiClient);
|
|
return wrapper?.Data?.FirstOrDefault();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting FCA individual: {IRN}", individualReferenceNumber);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<FcaFirmResponse?> SearchFirmsAsync(string name, int page = 1)
|
|
{
|
|
try
|
|
{
|
|
var encodedName = Uri.EscapeDataString(name);
|
|
var url = $"Firms?q={encodedName}&page={page}";
|
|
|
|
var response = await _httpClient.GetAsync(url);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return await response.Content.ReadFromJsonAsync<FcaFirmResponse>(JsonDefaults.ApiClient);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error searching FCA for firm: {Name}", name);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class FcaOptions
|
|
{
|
|
public string ApiKey { get; set; } = string.Empty;
|
|
public string Email { get; set; } = string.Empty;
|
|
}
|
|
|
|
// Response models
|
|
public class FcaIndividualResponse
|
|
{
|
|
public List<FcaIndividualSearchItem>? Data { get; set; }
|
|
public FcaPagination? Pagination { get; set; }
|
|
}
|
|
|
|
public class FcaIndividualSearchItem
|
|
{
|
|
[JsonPropertyName("Individual Reference Number")]
|
|
public string? IndividualReferenceNumber { get; set; }
|
|
|
|
public string? Name { get; set; }
|
|
public string? Status { get; set; }
|
|
|
|
[JsonPropertyName("Current Employer(s)")]
|
|
public string? CurrentEmployers { get; set; }
|
|
}
|
|
|
|
public class FcaIndividualDetailsWrapper
|
|
{
|
|
public List<FcaIndividualDetails>? Data { get; set; }
|
|
}
|
|
|
|
public class FcaIndividualDetails
|
|
{
|
|
[JsonPropertyName("Individual Reference Number")]
|
|
public string? IndividualReferenceNumber { get; set; }
|
|
|
|
public string? Name { get; set; }
|
|
public string? Status { get; set; }
|
|
|
|
[JsonPropertyName("Effective Date")]
|
|
public string? EffectiveDate { get; set; }
|
|
|
|
[JsonPropertyName("Controlled Functions")]
|
|
public List<FcaControlledFunction>? ControlledFunctions { get; set; }
|
|
|
|
[JsonPropertyName("Previous Employments")]
|
|
public List<FcaPreviousEmployment>? PreviousEmployments { get; set; }
|
|
}
|
|
|
|
public class FcaControlledFunction
|
|
{
|
|
[JsonPropertyName("Controlled Function")]
|
|
public string? ControlledFunction { get; set; }
|
|
|
|
[JsonPropertyName("Firm Name")]
|
|
public string? FirmName { get; set; }
|
|
|
|
[JsonPropertyName("Firm Reference Number")]
|
|
public string? FirmReferenceNumber { get; set; }
|
|
|
|
[JsonPropertyName("Status")]
|
|
public string? Status { get; set; }
|
|
|
|
[JsonPropertyName("Effective From")]
|
|
public string? EffectiveFrom { get; set; }
|
|
}
|
|
|
|
public class FcaPreviousEmployment
|
|
{
|
|
[JsonPropertyName("Firm Name")]
|
|
public string? FirmName { get; set; }
|
|
|
|
[JsonPropertyName("Firm Reference Number")]
|
|
public string? FirmReferenceNumber { get; set; }
|
|
|
|
[JsonPropertyName("Start Date")]
|
|
public string? StartDate { get; set; }
|
|
|
|
[JsonPropertyName("End Date")]
|
|
public string? EndDate { get; set; }
|
|
}
|
|
|
|
public class FcaFirmResponse
|
|
{
|
|
public List<FcaFirmSearchItem>? Data { get; set; }
|
|
public FcaPagination? Pagination { get; set; }
|
|
}
|
|
|
|
public class FcaFirmSearchItem
|
|
{
|
|
[JsonPropertyName("Firm Reference Number")]
|
|
public string? FirmReferenceNumber { get; set; }
|
|
|
|
[JsonPropertyName("Firm Name")]
|
|
public string? FirmName { get; set; }
|
|
|
|
public string? Status { get; set; }
|
|
}
|
|
|
|
public class FcaPagination
|
|
{
|
|
public int Page { get; set; }
|
|
public int TotalPages { get; set; }
|
|
public int TotalItems { get; set; }
|
|
}
|