refactor: Remove SRA integration (no public API available)

The SRA (Solicitors Regulation Authority) does not provide a public REST API.
Their register is only accessible via their website. Removed all SRA-related
code and added ApiTester tool for testing remaining integrations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-24 15:28:07 +00:00
parent ff09524503
commit 72b7f11c41
8 changed files with 137 additions and 392 deletions

View File

@@ -8,16 +8,13 @@ namespace RealCV.Infrastructure.Services;
public sealed class ProfessionalVerifierService : IProfessionalVerifierService
{
private readonly FcaRegisterClient _fcaClient;
private readonly SraRegisterClient _sraClient;
private readonly ILogger<ProfessionalVerifierService> _logger;
public ProfessionalVerifierService(
FcaRegisterClient fcaClient,
SraRegisterClient sraClient,
ILogger<ProfessionalVerifierService> logger)
{
_fcaClient = fcaClient;
_sraClient = sraClient;
_logger = logger;
}
@@ -148,150 +145,6 @@ public sealed class ProfessionalVerifierService : IProfessionalVerifierService
}
}
public async Task<ProfessionalVerificationResult> VerifySolicitorAsync(
string name,
string? sraNumber = null,
string? firmName = null)
{
try
{
_logger.LogInformation("Verifying SRA registration for: {Name}", name);
// If we have an SRA number, try to get directly
if (!string.IsNullOrEmpty(sraNumber))
{
var details = await _sraClient.GetSolicitorAsync(sraNumber);
if (details != null)
{
var isNameMatch = IsNameMatch(name, details.FullName);
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = isNameMatch,
RegistrationNumber = details.SraId,
MatchedName = details.FullName,
Status = details.Status,
AdmissionDate = details.AdmissionDate,
SolicitorType = details.SolicitorType,
PractisingCertificateStatus = details.PractisingCertificateStatus,
CurrentEmployer = details.CurrentPosition?.OrganisationName,
VerificationNotes = isNameMatch
? $"SRA ID: {details.SraId}"
: "SRA number found but name does not match",
Flags = details.DisciplinaryHistory?.Count > 0
? [new ProfessionalVerificationFlag
{
Type = "DisciplinaryRecord",
Severity = "Warning",
Message = $"Has {details.DisciplinaryHistory.Count} disciplinary record(s)",
ScoreImpact = -20
}]
: []
};
}
}
// Search by name
var searchResponse = await _sraClient.SearchSolicitorsAsync(name);
if (searchResponse?.Results == null || searchResponse.Results.Count == 0)
{
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = false,
VerificationNotes = "No matching SRA registered solicitors found"
};
}
// Find best match
var matches = searchResponse.Results
.Where(s => IsNameMatch(name, s.Name))
.ToList();
if (matches.Count == 0)
{
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = false,
VerificationNotes = $"Found {searchResponse.Results.Count} results but no close name matches"
};
}
// If firm specified, try to match on that too
SraSolicitorSearchItem? bestMatch = null;
if (!string.IsNullOrEmpty(firmName))
{
bestMatch = matches.FirstOrDefault(m =>
m.CurrentOrganisation?.Contains(firmName, StringComparison.OrdinalIgnoreCase) == true);
}
bestMatch ??= matches.First();
// Get detailed information
if (!string.IsNullOrEmpty(bestMatch.SraId))
{
var details = await _sraClient.GetSolicitorAsync(bestMatch.SraId);
if (details != null)
{
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = true,
RegistrationNumber = details.SraId,
MatchedName = details.FullName,
Status = details.Status,
AdmissionDate = details.AdmissionDate,
SolicitorType = details.SolicitorType,
PractisingCertificateStatus = details.PractisingCertificateStatus,
CurrentEmployer = details.CurrentPosition?.OrganisationName,
VerificationNotes = $"SRA ID: {details.SraId}",
Flags = details.DisciplinaryHistory?.Count > 0
? [new ProfessionalVerificationFlag
{
Type = "DisciplinaryRecord",
Severity = "Warning",
Message = $"Has {details.DisciplinaryHistory.Count} disciplinary record(s)",
ScoreImpact = -20
}]
: []
};
}
}
// Basic verification without details
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = true,
RegistrationNumber = bestMatch.SraId,
MatchedName = bestMatch.Name,
Status = bestMatch.Status,
AdmissionDate = bestMatch.AdmissionDate,
CurrentEmployer = bestMatch.CurrentOrganisation,
VerificationNotes = "Verified via SRA Register search"
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error verifying SRA registration for: {Name}", name);
return new ProfessionalVerificationResult
{
ClaimedName = name,
ProfessionalBody = "SRA",
IsVerified = false,
VerificationNotes = $"Error during verification: {ex.Message}"
};
}
}
public async Task<List<FcaIndividualSearchResult>> SearchFcaIndividualsAsync(string name)
{
try
@@ -323,35 +176,6 @@ public sealed class ProfessionalVerifierService : IProfessionalVerifierService
}
}
public async Task<List<SraSolicitorSearchResult>> SearchSolicitorsAsync(string name)
{
try
{
var searchResponse = await _sraClient.SearchSolicitorsAsync(name);
if (searchResponse?.Results == null)
{
return [];
}
return searchResponse.Results
.Select(s => new SraSolicitorSearchResult
{
Name = s.Name ?? "Unknown",
SraNumber = s.SraId ?? "Unknown",
Status = s.Status,
CurrentOrganisation = s.CurrentOrganisation,
AdmissionDate = s.AdmissionDate
})
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error searching SRA for: {Name}", name);
return [];
}
}
private static bool IsNameMatch(string searchName, string? foundName)
{
if (string.IsNullOrEmpty(foundName))