- GeradoresService: cada tipo passa a ser um IGenerator (NIF, NIPC, NISS, CC, passaporte, IBAN, NIB, cartões, referência MB, pessoa, telefone, código postal, email, matrícula, EAN, UUID) registado em GeneratorRegistry; remove DAL/EF - GeradoresWS: minimal APIs em /api/v1 com OpenAPI + Scalar e health check - UnitTest: testes de ida e volta, valores conhecidos, detecção e API - geradoresfe: UI construída a partir dos metadados da API, validador livre, exportação CSV/JSON/TXT, nginx com API_UPSTREAM configurável - Docker, docker-compose e Jenkinsfile actualizados Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
2.9 KiB
C#
86 lines
2.9 KiB
C#
using GeradoresService.Core;
|
|
using GeradoresService.Generators.Contactos;
|
|
using GeradoresService.Generators.Financeiro;
|
|
using GeradoresService.Generators.Identificacao;
|
|
using GeradoresService.Generators.Outros;
|
|
|
|
namespace GeradoresService;
|
|
|
|
public sealed record DetectionMatch(IGenerator Generator, ValidationResult Result);
|
|
|
|
public sealed class GeneratorRegistry
|
|
{
|
|
public const int MaxBatch = 1000;
|
|
|
|
public IReadOnlyList<IGenerator> All { get; }
|
|
|
|
public GeneratorRegistry() : this(
|
|
[
|
|
new NifGenerator(),
|
|
new NipcGenerator(),
|
|
new NissGenerator(),
|
|
new CartaoCidadaoGenerator(),
|
|
new PassaporteGenerator(),
|
|
new IbanGenerator(),
|
|
new NibGenerator(),
|
|
new CartaoCreditoGenerator(),
|
|
new ReferenciaMultibancoGenerator(),
|
|
new PessoaGenerator(),
|
|
new TelefoneGenerator(),
|
|
new CodigoPostalGenerator(),
|
|
new EmailGenerator(),
|
|
new MatriculaGenerator(),
|
|
new EanGenerator(),
|
|
new UuidGenerator(),
|
|
])
|
|
{ }
|
|
|
|
public GeneratorRegistry(IReadOnlyList<IGenerator> generators) => All = generators;
|
|
|
|
public IGenerator? Find(string id) =>
|
|
All.FirstOrDefault(g => string.Equals(g.Id, id, StringComparison.OrdinalIgnoreCase));
|
|
|
|
/// <summary>Gera <paramref name="count"/> valores. Um <paramref name="seed"/> torna o resultado reprodutível.</summary>
|
|
public IReadOnlyList<GeneratedItem> Generate(IGenerator generator, int count, IReadOnlyDictionary<string, string?> options, int? seed = null)
|
|
{
|
|
if (count is < 1 or > MaxBatch)
|
|
throw new ArgumentOutOfRangeException(nameof(count), $"A quantidade deve estar entre 1 e {MaxBatch}.");
|
|
|
|
var context = new GeneratorContext(seed is { } s ? new Random(s) : Random.Shared, options);
|
|
var items = new GeneratedItem[count];
|
|
for (var i = 0; i < count; i++)
|
|
items[i] = generator.Generate(context);
|
|
return items;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validador livre: tenta todos os tipos. Devolve primeiro os válidos, depois os que têm o formato
|
|
/// certo mas falham o controlo (ex.: "parece um NIF mas o dígito está errado").
|
|
/// </summary>
|
|
public IReadOnlyList<DetectionMatch> Detect(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
return [];
|
|
|
|
return All
|
|
.Where(g => g.CanValidate)
|
|
.Select(g => new DetectionMatch(g, SafeValidate(g, value)))
|
|
.Where(m => m.Result.FormatMatch)
|
|
.OrderByDescending(m => m.Result.IsValid)
|
|
.ThenByDescending(m => m.Generator.HasChecksum)
|
|
.ToList();
|
|
}
|
|
|
|
private static ValidationResult SafeValidate(IGenerator generator, string value)
|
|
{
|
|
try
|
|
{
|
|
return generator.Validate(value);
|
|
}
|
|
catch (Exception ex) when (ex is FormatException or ArgumentException or OverflowException)
|
|
{
|
|
return ValidationResult.WrongFormat(ex.Message);
|
|
}
|
|
}
|
|
}
|