feat: Add additional verification APIs (FCA, SRA, GitHub, OpenCorporates, ORCID)
This adds five new free API integrations for enhanced CV verification: - FCA Register API: Verify financial services professionals - SRA Register API: Verify solicitors and legal professionals - GitHub API: Verify developer profiles and technical skills - OpenCorporates API: Verify international companies across jurisdictions - ORCID API: Verify academic researchers and publications Includes: - API clients for all five services with retry policies - Service implementations with name matching and validation - Models for verification results with detailed flags - Configuration options in appsettings.json - DI registration for all services 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
using RealCV.Application.Models;
|
||||
|
||||
namespace RealCV.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for verifying academic researchers via ORCID
|
||||
/// </summary>
|
||||
public interface IAcademicVerifierService
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify an academic researcher by ORCID ID
|
||||
/// </summary>
|
||||
Task<AcademicVerificationResult> VerifyByOrcidAsync(string orcidId);
|
||||
|
||||
/// <summary>
|
||||
/// Search for researchers and verify by name
|
||||
/// </summary>
|
||||
Task<AcademicVerificationResult> VerifyByNameAsync(
|
||||
string name,
|
||||
string? affiliation = null);
|
||||
|
||||
/// <summary>
|
||||
/// Search ORCID for researchers
|
||||
/// </summary>
|
||||
Task<List<OrcidSearchResult>> SearchResearchersAsync(
|
||||
string name,
|
||||
string? affiliation = null);
|
||||
|
||||
/// <summary>
|
||||
/// Verify claimed publications
|
||||
/// </summary>
|
||||
Task<List<PublicationVerificationResult>> VerifyPublicationsAsync(
|
||||
string orcidId,
|
||||
List<string> claimedPublications);
|
||||
}
|
||||
|
||||
public sealed record OrcidSearchResult
|
||||
{
|
||||
public required string OrcidId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public string? OrcidUrl { get; init; }
|
||||
public List<string>? Affiliations { get; init; }
|
||||
public int? PublicationCount { get; init; }
|
||||
}
|
||||
|
||||
public sealed record PublicationVerificationResult
|
||||
{
|
||||
public required string ClaimedTitle { get; init; }
|
||||
public required bool IsVerified { get; init; }
|
||||
public string? MatchedTitle { get; init; }
|
||||
public string? Doi { get; init; }
|
||||
public int? Year { get; init; }
|
||||
public string? Notes { get; init; }
|
||||
}
|
||||
36
src/RealCV.Application/Interfaces/IGitHubVerifierService.cs
Normal file
36
src/RealCV.Application/Interfaces/IGitHubVerifierService.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using RealCV.Application.Models;
|
||||
|
||||
namespace RealCV.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for verifying developer profiles and skills via GitHub
|
||||
/// </summary>
|
||||
public interface IGitHubVerifierService
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify a GitHub profile and analyze activity
|
||||
/// </summary>
|
||||
Task<GitHubVerificationResult> VerifyProfileAsync(string username);
|
||||
|
||||
/// <summary>
|
||||
/// Verify claimed programming skills against GitHub activity
|
||||
/// </summary>
|
||||
Task<GitHubVerificationResult> VerifySkillsAsync(
|
||||
string username,
|
||||
List<string> claimedSkills);
|
||||
|
||||
/// <summary>
|
||||
/// Search for GitHub profiles matching a name
|
||||
/// </summary>
|
||||
Task<List<GitHubProfileSearchResult>> SearchProfilesAsync(string name);
|
||||
}
|
||||
|
||||
public sealed record GitHubProfileSearchResult
|
||||
{
|
||||
public required string Username { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? AvatarUrl { get; init; }
|
||||
public string? Bio { get; init; }
|
||||
public int PublicRepos { get; init; }
|
||||
public int Followers { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using RealCV.Application.Models;
|
||||
|
||||
namespace RealCV.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for verifying international companies via OpenCorporates
|
||||
/// </summary>
|
||||
public interface IInternationalCompanyVerifierService
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify an international company
|
||||
/// </summary>
|
||||
Task<InternationalCompanyResult> VerifyCompanyAsync(
|
||||
string companyName,
|
||||
string? jurisdiction = null,
|
||||
DateOnly? claimedStartDate = null,
|
||||
DateOnly? claimedEndDate = null);
|
||||
|
||||
/// <summary>
|
||||
/// Search for companies across all jurisdictions
|
||||
/// </summary>
|
||||
Task<List<OpenCorporatesSearchResult>> SearchCompaniesAsync(
|
||||
string query,
|
||||
string? jurisdiction = null);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of supported jurisdictions
|
||||
/// </summary>
|
||||
Task<List<JurisdictionInfo>> GetJurisdictionsAsync();
|
||||
}
|
||||
|
||||
public sealed record OpenCorporatesSearchResult
|
||||
{
|
||||
public required string CompanyName { get; init; }
|
||||
public required string CompanyNumber { get; init; }
|
||||
public required string Jurisdiction { get; init; }
|
||||
public string? JurisdictionCode { get; init; }
|
||||
public string? Status { get; init; }
|
||||
public DateOnly? IncorporationDate { get; init; }
|
||||
public string? OpenCorporatesUrl { get; init; }
|
||||
public double? MatchScore { get; init; }
|
||||
}
|
||||
|
||||
public sealed record JurisdictionInfo
|
||||
{
|
||||
public required string Code { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public string? Country { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using RealCV.Application.Models;
|
||||
|
||||
namespace RealCV.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for verifying professional qualifications (FCA, SRA, etc.)
|
||||
/// </summary>
|
||||
public interface IProfessionalVerifierService
|
||||
{
|
||||
/// <summary>
|
||||
/// Verify if a person is registered with the FCA
|
||||
/// </summary>
|
||||
Task<ProfessionalVerificationResult> VerifyFcaRegistrationAsync(
|
||||
string name,
|
||||
string? firmName = null,
|
||||
string? referenceNumber = null);
|
||||
|
||||
/// <summary>
|
||||
/// Verify if a person is a registered solicitor with the SRA
|
||||
/// </summary>
|
||||
Task<ProfessionalVerificationResult> VerifySolicitorAsync(
|
||||
string name,
|
||||
string? sraNumber = null,
|
||||
string? firmName = null);
|
||||
|
||||
/// <summary>
|
||||
/// Search FCA register for individuals
|
||||
/// </summary>
|
||||
Task<List<FcaIndividualSearchResult>> SearchFcaIndividualsAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Search SRA register for solicitors
|
||||
/// </summary>
|
||||
Task<List<SraSolicitorSearchResult>> SearchSolicitorsAsync(string name);
|
||||
}
|
||||
|
||||
public sealed record FcaIndividualSearchResult
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required string IndividualReferenceNumber { get; init; }
|
||||
public string? Status { get; init; }
|
||||
public List<string>? CurrentFirms { get; init; }
|
||||
}
|
||||
|
||||
public sealed record SraSolicitorSearchResult
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required string SraNumber { get; init; }
|
||||
public string? Status { get; init; }
|
||||
public string? CurrentOrganisation { get; init; }
|
||||
public string? AdmissionDate { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user