add validation and remove debug and add errorlogs
This commit is contained in:
parent
0f673c6a6e
commit
3c036a4891
13 changed files with 224 additions and 30 deletions
|
|
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
using AuthAPI;
|
using AuthAPI;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
builder.Logging.SetMinimumLevel(LogLevel.Error);
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
builder.Services.Configure<AuthSettings>(
|
builder.Services.Configure<AuthSettings>(
|
||||||
builder.Configuration.GetSection("EnvironmentVariables"));
|
builder.Configuration.GetSection("EnvironmentVariables"));
|
||||||
|
|
@ -18,7 +19,8 @@ app.MapPost("/validate", async (
|
||||||
[FromBody] Request validationRequest,
|
[FromBody] Request validationRequest,
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
MemberValidationService memberService,
|
MemberValidationService memberService,
|
||||||
IOptions<AuthSettings> settings) =>
|
IOptions<AuthSettings> settings,
|
||||||
|
ILogger<Program> logger) =>
|
||||||
{
|
{
|
||||||
var request = memberService.GetRequestWithApiKey(validationRequest);
|
var request = memberService.GetRequestWithApiKey(validationRequest);
|
||||||
if (request.IsFailure)
|
if (request.IsFailure)
|
||||||
|
|
@ -29,10 +31,12 @@ app.MapPost("/validate", async (
|
||||||
request.Success);
|
request.Success);
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
logger.LogError("Sverok validation returned non-success status code: {StatusCode}", (int)response.StatusCode);
|
||||||
return Results.StatusCode((int)response.StatusCode);
|
return Results.StatusCode((int)response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
var content = await response.Content.ReadAsStringAsync();
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
Console.WriteLine($"[DEBUG] Sverok response: {content}");
|
|
||||||
return content.Contains("\"member_found\":true") ? Results.Ok() : Results.NotFound();
|
return content.Contains("\"member_found\":true") ? Results.Ok() : Results.NotFound();
|
||||||
})
|
})
|
||||||
.WithName("ValidateMember");
|
.WithName("ValidateMember");
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,5 @@ public class VbytesRelayOptions
|
||||||
public string ApiKeyHeaderName { get; set; } = "X-Api-Key";
|
public string ApiKeyHeaderName { get; set; } = "X-Api-Key";
|
||||||
public string ApiKey { get; set; } = string.Empty;
|
public string ApiKey { get; set; } = string.Empty;
|
||||||
public string ClientCertificatePfxPath { get; set; } = string.Empty;
|
public string ClientCertificatePfxPath { get; set; } = string.Empty;
|
||||||
public string VolunteerRegisterPath { get; set; } = "/api/volunteer/register";
|
public string VolunteerRegisterPath { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Registration.API.RequestModels;
|
||||||
using Registration.API.Services;
|
using Registration.API.Services;
|
||||||
|
using Registration.API.Validation;
|
||||||
using Registration.Domain.Models;
|
using Registration.Domain.Models;
|
||||||
|
|
||||||
namespace Registration.API.Controllers;
|
namespace Registration.API.Controllers;
|
||||||
|
|
@ -11,8 +13,33 @@ public class ParticipantController(IVbytesParticipantRelayService relayService)
|
||||||
private readonly IVbytesParticipantRelayService _relayService = relayService;
|
private readonly IVbytesParticipantRelayService _relayService = relayService;
|
||||||
|
|
||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
public async Task<IActionResult> RegisterForLan([FromBody] Participant participant, CancellationToken cancellationToken)
|
public async Task<IActionResult> RegisterForLan([FromBody] ParticipantRegistrationRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var normalizedGuardianPhone = InputNormalization.NormalizeSwedishMobile(request.GuardianPhoneNumber);
|
||||||
|
|
||||||
|
string? normalizedParticipantPhone = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.PhoneNumber))
|
||||||
|
{
|
||||||
|
normalizedParticipantPhone = InputNormalization.NormalizeSwedishMobile(request.PhoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
var participant = new Participant
|
||||||
|
{
|
||||||
|
IsMember = request.IsMember!.Value,
|
||||||
|
FirstName = request.FirstName.Trim(),
|
||||||
|
SurName = request.SurName.Trim(),
|
||||||
|
Grade = request.Grade.Trim(),
|
||||||
|
PhoneNumber = normalizedParticipantPhone,
|
||||||
|
Email = request.Email?.Trim(),
|
||||||
|
GuardianName = request.GuardianName.Trim(),
|
||||||
|
GuardianPhoneNumber = normalizedGuardianPhone,
|
||||||
|
GuardianEmail = request.GuardianEmail.Trim(),
|
||||||
|
IsVisitor = request.IsVisitor!.Value,
|
||||||
|
HasApprovedGdpr = request.HasApprovedGdpr!.Value,
|
||||||
|
Friends = request.Friends?.Trim(),
|
||||||
|
SpecialDiet = request.SpecialDiet?.Trim(),
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken);
|
var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken);
|
||||||
|
|
||||||
if (result.StatusCode == 200 && !result.Message.Contains("401"))
|
if (result.StatusCode == 200 && !result.Message.Contains("401"))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Registration.API.Services;
|
using Registration.API.Services;
|
||||||
|
using Registration.API.Validation;
|
||||||
using Registration.Infra.Repositories;
|
using Registration.Infra.Repositories;
|
||||||
|
|
||||||
namespace Registration.API.Controllers
|
namespace Registration.API.Controllers
|
||||||
|
|
@ -14,14 +15,24 @@ namespace Registration.API.Controllers
|
||||||
[HttpGet("register/{ssn}")]
|
[HttpGet("register/{ssn}")]
|
||||||
public async Task<IActionResult> ValidateSsn(string ssn, CancellationToken cancellationToken)
|
public async Task<IActionResult> ValidateSsn(string ssn, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var isMember = await _authService.IsMemberAsync(ssn, cancellationToken);
|
if (!TryNormalizeSsn(ssn, out var normalizedSsn, out var errorResult))
|
||||||
|
{
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMember = await _authService.IsMemberAsync(normalizedSsn, cancellationToken);
|
||||||
return isMember ? Ok() : NotFound();
|
return isMember ? Ok() : NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("register/{ssn}")]
|
[HttpPost("register/{ssn}")]
|
||||||
public async Task<IActionResult> RegisterMember(string ssn)
|
public async Task<IActionResult> RegisterMember(string ssn)
|
||||||
{
|
{
|
||||||
var added = await _memberRepository.AddRegistration(ssn);
|
if (!TryNormalizeSsn(ssn, out var normalizedSsn, out var errorResult))
|
||||||
|
{
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
var added = await _memberRepository.AddRegistration(normalizedSsn);
|
||||||
|
|
||||||
return added ? Ok() : Conflict();
|
return added ? Ok() : Conflict();
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +40,12 @@ namespace Registration.API.Controllers
|
||||||
[HttpGet("registered/{ssn}")]
|
[HttpGet("registered/{ssn}")]
|
||||||
public async Task<IActionResult> IsMemberRegistered(string ssn)
|
public async Task<IActionResult> IsMemberRegistered(string ssn)
|
||||||
{
|
{
|
||||||
var isRegistered = await _memberRepository.GetIsRegistered(ssn);
|
if (!TryNormalizeSsn(ssn, out var normalizedSsn, out var errorResult))
|
||||||
|
{
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isRegistered = await _memberRepository.GetIsRegistered(normalizedSsn);
|
||||||
return isRegistered ? Conflict() : Ok();
|
return isRegistered ? Conflict() : Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,5 +55,25 @@ namespace Registration.API.Controllers
|
||||||
await _memberRepository.ClearRegistrations();
|
await _memberRepository.ClearRegistrations();
|
||||||
return Ok(new { Message = "All registrations cleared." });
|
return Ok(new { Message = "All registrations cleared." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryNormalizeSsn(string ssn, out string normalizedSsn, out IActionResult errorResult)
|
||||||
|
{
|
||||||
|
normalizedSsn = InputNormalization.NormalizeSsn(ssn);
|
||||||
|
if (InputNormalization.IsValidSsn(normalizedSsn))
|
||||||
|
{
|
||||||
|
errorResult = Ok();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorResult = BadRequest(new ValidationProblemDetails(new Dictionary<string, string[]>
|
||||||
|
{
|
||||||
|
["ssn"] = ["SSN must contain 10 or 12 digits."]
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Title = "One or more validation errors occurred.",
|
||||||
|
Status = StatusCodes.Status400BadRequest
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Registration.API.RequestModels;
|
||||||
using Registration.API.Services;
|
using Registration.API.Services;
|
||||||
|
using Registration.API.Validation;
|
||||||
using Registration.Domain.Models;
|
using Registration.Domain.Models;
|
||||||
|
|
||||||
namespace Registration.API.Controllers;
|
namespace Registration.API.Controllers;
|
||||||
|
|
@ -11,8 +13,35 @@ public class VolunteerController(IVbytesVolunteerRelayService relayService) : Co
|
||||||
private readonly IVbytesVolunteerRelayService _relayService = relayService;
|
private readonly IVbytesVolunteerRelayService _relayService = relayService;
|
||||||
|
|
||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
public async Task<IActionResult> RegisterVolunteer([FromBody] Volunteer volunteer, CancellationToken cancellationToken)
|
public async Task<IActionResult> RegisterVolunteer([FromBody] VolunteerRegistrationRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var normalizedPhone = InputNormalization.NormalizeSwedishMobile(request.PhoneNumber);
|
||||||
|
|
||||||
|
var trimmedAreas = request.AreasOfInterest
|
||||||
|
.Select(area => area.Name.Trim())
|
||||||
|
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (trimmedAreas.Count == 0)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(request.AreasOfInterest), "At least one valid area of interest is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return ValidationProblem(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var volunteer = new Volunteer
|
||||||
|
{
|
||||||
|
FirstName = request.FirstName.Trim(),
|
||||||
|
SurName = request.SurName.Trim(),
|
||||||
|
PhoneNumber = normalizedPhone,
|
||||||
|
Email = request.Email.Trim(),
|
||||||
|
HasApprovedGdpr = request.HasApprovedGdpr!.Value,
|
||||||
|
AreasOfInterest = trimmedAreas.Select(name => new AreasOfInterest { Name = name }).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _relayService.RegisterVolunteerAsync(volunteer, cancellationToken);
|
var result = await _relayService.RegisterVolunteerAsync(volunteer, cancellationToken);
|
||||||
|
|
||||||
if (result.StatusCode == 200 && !result.Message.Contains("401"))
|
if (result.StatusCode == 200 && !result.Message.Contains("401"))
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Registration.API.Configuration;
|
||||||
using Registration.API.Services;
|
using Registration.API.Services;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
builder.Logging.SetMinimumLevel(LogLevel.Error);
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Registration.API.RequestModels;
|
||||||
|
|
||||||
|
public class AreaOfInterestRequest
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Registration.API.RequestModels;
|
||||||
|
|
||||||
|
public class ParticipantRegistrationRequest
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public bool? IsMember { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string FirstName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string SurName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Grade { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
|
||||||
|
[EmailAddress]
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string GuardianName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string GuardianPhoneNumber { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string GuardianEmail { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool? IsVisitor { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool? HasApprovedGdpr { get; set; }
|
||||||
|
|
||||||
|
public string? Friends { get; set; }
|
||||||
|
|
||||||
|
public string? SpecialDiet { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Registration.API.RequestModels;
|
||||||
|
|
||||||
|
public class VolunteerRegistrationRequest
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string FirstName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string SurName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string PhoneNumber { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool? HasApprovedGdpr { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[MinLength(1)]
|
||||||
|
public List<AreaOfInterestRequest> AreasOfInterest { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ public class VbytesParticipantRelayService(
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options,
|
IOptions<VbytesRelayOptions> options,
|
||||||
ILogger<VbytesParticipantRelayService> logger)
|
ILogger<VbytesParticipantRelayService> logger)
|
||||||
: VbytesRelayServiceBase(httpClient, options), IVbytesParticipantRelayService
|
: VbytesRelayServiceBase(httpClient, options, logger), IVbytesParticipantRelayService
|
||||||
{
|
{
|
||||||
public const string HttpClientName = "VbytesRelay";
|
public const string HttpClientName = "VbytesRelay";
|
||||||
|
|
||||||
|
|
@ -20,24 +20,22 @@ public class VbytesParticipantRelayService(
|
||||||
var configError = ValidateConfiguration();
|
var configError = ValidateConfiguration();
|
||||||
if (configError is not null)
|
if (configError is not null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Relay configuration invalid: {Message}", configError.Message);
|
_logger.LogError("Relay configuration invalid: {Message}", configError.Message);
|
||||||
|
|
||||||
return configError;
|
return configError;
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = Map(participant);
|
var payload = Map(participant);
|
||||||
_logger.LogInformation("Relaying participant to {Path}. Payload: {@Payload}", Options.ParticipantRegisterPath, payload);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await SendAsync(Options.ParticipantRegisterPath, payload, cancellationToken);
|
var result = await SendAsync(Options.ParticipantRegisterPath, payload, cancellationToken);
|
||||||
_logger.LogInformation("Relay response: {StatusCode} - {Message}", result.StatusCode, result.Message);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (TaskCanceledException)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Relay timed out calling {Path}", Options.ParticipantRegisterPath);
|
_logger.LogError("Relay timed out calling {Path}", Options.ParticipantRegisterPath);
|
||||||
|
|
||||||
return new VbytesRelayResult(false, StatusCodes.Status504GatewayTimeout, "Upstream timeout.");
|
return new VbytesRelayResult(false, StatusCodes.Status504GatewayTimeout, "Upstream timeout.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Registration.API.Configuration;
|
using Registration.API.Configuration;
|
||||||
|
|
||||||
|
|
@ -6,9 +5,11 @@ namespace Registration.API.Services;
|
||||||
|
|
||||||
public abstract class VbytesRelayServiceBase(
|
public abstract class VbytesRelayServiceBase(
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options)
|
IOptions<VbytesRelayOptions> options,
|
||||||
|
ILogger logger)
|
||||||
{
|
{
|
||||||
private readonly HttpClient _httpClient = httpClient;
|
private readonly HttpClient _httpClient = httpClient;
|
||||||
|
private readonly ILogger _logger = logger;
|
||||||
protected readonly VbytesRelayOptions Options = options.Value;
|
protected readonly VbytesRelayOptions Options = options.Value;
|
||||||
|
|
||||||
protected async Task<VbytesRelayResult> SendAsync(string path, object payload, CancellationToken cancellationToken)
|
protected async Task<VbytesRelayResult> SendAsync(string path, object payload, CancellationToken cancellationToken)
|
||||||
|
|
@ -22,16 +23,16 @@ public abstract class VbytesRelayServiceBase(
|
||||||
|
|
||||||
using var response = await _httpClient.SendAsync(request, cancellationToken);
|
using var response = await _httpClient.SendAsync(request, cancellationToken);
|
||||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||||
|
var safeBody = body.Length > 600 ? body[..600] : body;
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[DEBUG] Relay success body: {body}");
|
|
||||||
return new VbytesRelayResult(true, StatusCodes.Status200OK, body);
|
return new VbytesRelayResult(true, StatusCodes.Status200OK, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
var statusCode = (int)response.StatusCode;
|
var statusCode = (int)response.StatusCode;
|
||||||
Console.WriteLine($"[DEBUG] Relay error body: {body}");
|
_logger.LogError("Outbound relay response error: {StatusCode}. Body: {Body}", statusCode, safeBody);
|
||||||
var message = body.Length > 600 ? body[..600] : body;
|
var message = safeBody;
|
||||||
return new VbytesRelayResult(false, statusCode, string.IsNullOrWhiteSpace(message) ? "Upstream request failed." : message);
|
return new VbytesRelayResult(false, statusCode, string.IsNullOrWhiteSpace(message) ? "Upstream request failed." : message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,17 +61,6 @@ public abstract class VbytesRelayServiceBase(
|
||||||
return path.StartsWith('/') ? path : $"/{path}";
|
return path.StartsWith('/') ? path : $"/{path}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> ReadSafeErrorMessage(HttpResponseMessage response, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
||||||
if (string.IsNullOrWhiteSpace(body))
|
|
||||||
{
|
|
||||||
return "Upstream request failed.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return body.Length > 600 ? body[..600] : body;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static bool IsConfigured(string value)
|
protected static bool IsConfigured(string value)
|
||||||
{
|
{
|
||||||
return !string.IsNullOrWhiteSpace(value) && !value.StartsWith("__SET_", StringComparison.Ordinal);
|
return !string.IsNullOrWhiteSpace(value) && !value.StartsWith("__SET_", StringComparison.Ordinal);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ public class VbytesVolunteerRelayService(
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options,
|
IOptions<VbytesRelayOptions> options,
|
||||||
ILogger<VbytesVolunteerRelayService> logger)
|
ILogger<VbytesVolunteerRelayService> logger)
|
||||||
: VbytesRelayServiceBase(httpClient, options), IVbytesVolunteerRelayService
|
: VbytesRelayServiceBase(httpClient, options, logger), IVbytesVolunteerRelayService
|
||||||
{
|
{
|
||||||
private readonly ILogger<VbytesVolunteerRelayService> _logger = logger;
|
private readonly ILogger<VbytesVolunteerRelayService> _logger = logger;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Registration.API.Validation;
|
||||||
|
|
||||||
|
public static partial class InputNormalization
|
||||||
|
{
|
||||||
|
public static string NormalizeSsn(string value)
|
||||||
|
{
|
||||||
|
var raw = value ?? string.Empty;
|
||||||
|
return NonDigitsRegex().Replace(raw, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsValidSsn(string value)
|
||||||
|
{
|
||||||
|
return value.Length is 10 or 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NormalizeSwedishMobile(string value)
|
||||||
|
{
|
||||||
|
var digitsOnly = NonDigitsRegex().Replace(value ?? string.Empty, string.Empty);
|
||||||
|
|
||||||
|
if (digitsOnly.StartsWith("0046")) return $"0{digitsOnly[4..]}";
|
||||||
|
if (digitsOnly.StartsWith("46")) return $"0{digitsOnly[2..]}";
|
||||||
|
if (digitsOnly.StartsWith('7')) return $"0{digitsOnly}";
|
||||||
|
|
||||||
|
return digitsOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex("\\D")]
|
||||||
|
private static partial Regex NonDigitsRegex();
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue