Reescrita dos geradores: biblioteca IGenerator, minimal API e novo frontend
- 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>
This commit is contained in:
56
GeradoresService/Generators/Contactos/EmailGenerator.cs
Normal file
56
GeradoresService/Generators/Contactos/EmailGenerator.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Globalization;
|
||||
using System.Net.Mail;
|
||||
using System.Text;
|
||||
using GeradoresService.Core;
|
||||
using GeradoresService.Data;
|
||||
|
||||
namespace GeradoresService.Generators.Contactos;
|
||||
|
||||
public sealed class EmailGenerator : GeneratorBase
|
||||
{
|
||||
public override string Id => "email";
|
||||
public override string Name => "Email";
|
||||
public override string Category => Categories.Contactos;
|
||||
public override string Description => "Endereço de email fictício. Por omissão usa domínios reservados para testes (example.com).";
|
||||
public override bool HasChecksum => false;
|
||||
|
||||
public override IReadOnlyList<GeneratorOption> Options =>
|
||||
[
|
||||
Option("dominio", "Domínio", "teste",
|
||||
("teste", "Reservado para testes (example.com)"),
|
||||
("realista", "Realista (gmail.com, sapo.pt…)")),
|
||||
];
|
||||
|
||||
public override GeneratedItem Generate(GeneratorContext context)
|
||||
{
|
||||
var first = context.Random.Next(2) == 0 ? context.Pick(PtData.MaleNames) : context.Pick(PtData.FemaleNames);
|
||||
return new GeneratedItem(Build(first, context.Pick(PtData.Surnames), context, context.Option(Options[0]) == "realista"));
|
||||
}
|
||||
|
||||
public static string Build(string firstName, string surname, GeneratorContext context, bool realistic = false)
|
||||
{
|
||||
var domains = realistic ? PtData.RealisticEmailDomains : PtData.SafeEmailDomains;
|
||||
var separator = context.Pick([".", "_", ""]);
|
||||
var suffix = context.Random.Next(3) == 0 ? context.Random.Next(1, 100).ToString() : "";
|
||||
return $"{Slug(firstName)}{separator}{Slug(surname)}{suffix}@{context.Pick(domains)}";
|
||||
}
|
||||
|
||||
private static string Slug(string s)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var c in s.Normalize(NormalizationForm.FormD))
|
||||
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark && char.IsLetterOrDigit(c))
|
||||
sb.Append(char.ToLowerInvariant(c));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override ValidationResult Validate(string value)
|
||||
{
|
||||
var v = value.Trim();
|
||||
var at = v.LastIndexOf('@');
|
||||
if (at <= 0 || at == v.Length - 1 || !v[(at + 1)..].Contains('.') || v.Any(char.IsWhiteSpace)
|
||||
|| !MailAddress.TryCreate(v, out var address) || address.Address != v)
|
||||
return ValidationResult.WrongFormat("Não é um endereço de email válido.");
|
||||
return ValidationResult.Valid(v.ToLowerInvariant(), "Formato de email válido.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user