quick fix
This commit is contained in:
parent
9d9c9b3f38
commit
a0d98b4d77
8 changed files with 72 additions and 64 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -6,9 +6,10 @@
|
||||||
# dotenv files
|
# dotenv files
|
||||||
.env
|
.env
|
||||||
|
|
||||||
*www.api.vbytes.se.key
|
*.key
|
||||||
*www.api.vbytes.se.csr
|
*.csr
|
||||||
*www.api.vbytes.se.crt
|
*.crt
|
||||||
|
*.pfx
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
using Registration.API.Services;
|
using Registration.API.Services;
|
||||||
using Registration.Domain.Models;
|
using Registration.Domain.Models;
|
||||||
|
|
||||||
namespace Registration.API.Controllers
|
namespace Registration.API.Controllers;
|
||||||
{
|
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class ParticipantController(IVbytesParticipantRelayService relayService) : ControllerBase
|
public class ParticipantController(IVbytesParticipantRelayService relayService) : ControllerBase
|
||||||
|
|
@ -15,12 +15,11 @@ namespace Registration.API.Controllers
|
||||||
{
|
{
|
||||||
var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken);
|
var result = await _relayService.RegisterParticipantAsync(participant, cancellationToken);
|
||||||
|
|
||||||
if (result.Success)
|
if (result.StatusCode == 200 && !result.Message.Contains("401"))
|
||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
return StatusCode(result.StatusCode, new { message = result.Message });
|
return Unauthorized();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,42 @@ builder.Services.AddScoped<IMemberRepository, MemberRepository>();
|
||||||
var relayOptions = builder.Configuration.GetSection("VbytesRelay").Get<VbytesRelayOptions>()
|
var relayOptions = builder.Configuration.GetSection("VbytesRelay").Get<VbytesRelayOptions>()
|
||||||
?? throw new InvalidOperationException("VbytesRelay configuration section is missing.");
|
?? throw new InvalidOperationException("VbytesRelay configuration section is missing.");
|
||||||
|
|
||||||
builder.Services.Configure<VbytesRelayOptions>(builder.Configuration.GetSection("VbytesRelay"));
|
|
||||||
|
|
||||||
|
|
||||||
var certificate = X509CertificateLoader.LoadPkcs12FromFile(
|
var certificate = X509CertificateLoader.LoadPkcs12FromFile(
|
||||||
relayOptions.ClientCertificatePfxPath, password: null);
|
relayOptions.ClientCertificatePfxPath, password: null);
|
||||||
|
|
||||||
builder.Services.AddHttpClient(VbytesParticipantRelayService.HttpClientName, client =>
|
builder.Services.AddSingleton(sp =>
|
||||||
{
|
{
|
||||||
client.BaseAddress = new Uri(relayOptions.BaseUrl);
|
var handler = new HttpClientHandler();
|
||||||
client.Timeout = TimeSpan.FromSeconds(30);
|
handler.ClientCertificates.Add(certificate);
|
||||||
|
return handler;
|
||||||
|
});
|
||||||
|
|
||||||
|
var authApiOptions = builder.Configuration.GetSection("AuthApi").Get<AuthApiOptions>()
|
||||||
|
?? throw new InvalidOperationException("AuthApi configuration section is missing.");
|
||||||
|
|
||||||
|
builder.Services.Configure<VbytesRelayOptions>(builder.Configuration.GetSection("VbytesRelay"));
|
||||||
|
|
||||||
|
|
||||||
|
builder.Services.AddHttpClient<IVbytesParticipantRelayService, VbytesParticipantRelayService>(o =>
|
||||||
|
{
|
||||||
|
o.BaseAddress = new Uri(relayOptions.BaseUrl) ??
|
||||||
|
throw new InvalidOperationException("BaseUrl is missing in VbytesRelay configuration.");
|
||||||
|
o.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
})
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService<HttpClientHandler>());
|
||||||
|
|
||||||
|
builder.Services.AddHttpClient<IVbytesVolunteerRelayService, VbytesVolunteerRelayService>(o =>
|
||||||
|
{
|
||||||
|
o.BaseAddress = new Uri(relayOptions.BaseUrl);
|
||||||
|
o.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
})
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService<HttpClientHandler>());
|
||||||
|
|
||||||
|
builder.Services.Configure<AuthApiOptions>(builder.Configuration.GetSection("AuthApi"));
|
||||||
|
builder.Services.AddHttpClient<IAuthService, AuthService>(o =>
|
||||||
|
{
|
||||||
|
o.BaseAddress = new Uri(authApiOptions.BaseUrl);
|
||||||
|
o.Timeout = TimeSpan.FromSeconds(10);
|
||||||
})
|
})
|
||||||
.ConfigurePrimaryHttpMessageHandler(() =>
|
.ConfigurePrimaryHttpMessageHandler(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -30,20 +56,6 @@ builder.Services.AddHttpClient(VbytesParticipantRelayService.HttpClientName, cli
|
||||||
return handler;
|
return handler;
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped<IVbytesParticipantRelayService, VbytesParticipantRelayService>();
|
|
||||||
builder.Services.AddScoped<IVbytesVolunteerRelayService, VbytesVolunteerRelayService>();
|
|
||||||
|
|
||||||
var authApiOptions = builder.Configuration.GetSection("AuthApi").Get<AuthApiOptions>()
|
|
||||||
?? throw new InvalidOperationException("AuthApi configuration section is missing.");
|
|
||||||
|
|
||||||
builder.Services.Configure<AuthApiOptions>(builder.Configuration.GetSection("AuthApi"));
|
|
||||||
builder.Services.AddHttpClient(AuthService.HttpClientName, client =>
|
|
||||||
{
|
|
||||||
client.BaseAddress = new Uri(authApiOptions.BaseUrl);
|
|
||||||
client.Timeout = TimeSpan.FromSeconds(10);
|
|
||||||
});
|
|
||||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,18 @@ using Registration.API.Configuration;
|
||||||
|
|
||||||
namespace Registration.API.Services;
|
namespace Registration.API.Services;
|
||||||
|
|
||||||
public class AuthService(IHttpClientFactory httpClientFactory, IOptions<AuthApiOptions> options) : IAuthService
|
public class AuthService(HttpClient httpClient, IOptions<AuthApiOptions> options) : IAuthService
|
||||||
{
|
{
|
||||||
public const string HttpClientName = "AuthApi";
|
public const string HttpClientName = "AuthApi";
|
||||||
|
private readonly HttpClient _httpClient = httpClient;
|
||||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
|
||||||
private readonly AuthApiOptions _options = options.Value;
|
private readonly AuthApiOptions _options = options.Value;
|
||||||
|
|
||||||
public async Task<bool> IsMemberAsync(string ssn, CancellationToken cancellationToken = default)
|
public async Task<bool> IsMemberAsync(string ssn, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var client = _httpClientFactory.CreateClient(HttpClientName);
|
var response = await _httpClient.PostAsJsonAsync(
|
||||||
var response = await client.PostAsJsonAsync(
|
|
||||||
_options.ValidatePath,
|
_options.ValidatePath,
|
||||||
new { ssn },
|
new { ssn },
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
return response.IsSuccessStatusCode;
|
return (int)response.StatusCode == StatusCodes.Status200OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ using Registration.Domain.Models;
|
||||||
namespace Registration.API.Services;
|
namespace Registration.API.Services;
|
||||||
|
|
||||||
public class VbytesParticipantRelayService(
|
public class VbytesParticipantRelayService(
|
||||||
IHttpClientFactory httpClientFactory,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options,
|
IOptions<VbytesRelayOptions> options,
|
||||||
ILogger<VbytesParticipantRelayService> logger)
|
ILogger<VbytesParticipantRelayService> logger)
|
||||||
: VbytesRelayServiceBase(httpClientFactory, options), IVbytesParticipantRelayService
|
: VbytesRelayServiceBase(httpClient, options), IVbytesParticipantRelayService
|
||||||
{
|
{
|
||||||
public const string HttpClientName = "VbytesRelay";
|
public const string HttpClientName = "VbytesRelay";
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@ public class VbytesParticipantRelayService(
|
||||||
if (configError is not null)
|
if (configError is not null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Relay configuration invalid: {Message}", configError.Message);
|
_logger.LogWarning("Relay configuration invalid: {Message}", configError.Message);
|
||||||
|
|
||||||
return configError;
|
return configError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,16 +32,19 @@ public class VbytesParticipantRelayService(
|
||||||
{
|
{
|
||||||
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);
|
_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.LogWarning("Relay timed out calling {Path}", Options.ParticipantRegisterPath);
|
||||||
|
|
||||||
return new VbytesRelayResult(false, StatusCodes.Status504GatewayTimeout, "Upstream timeout.");
|
return new VbytesRelayResult(false, StatusCodes.Status504GatewayTimeout, "Upstream timeout.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "VBytes participant relay exception.");
|
_logger.LogError(ex, "VBytes participant relay exception.");
|
||||||
|
|
||||||
return new VbytesRelayResult(false, StatusCodes.Status502BadGateway, "Upstream relay failed.");
|
return new VbytesRelayResult(false, StatusCodes.Status502BadGateway, "Upstream relay failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
using System.Net.Http.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Registration.API.Configuration;
|
using Registration.API.Configuration;
|
||||||
|
|
||||||
namespace Registration.API.Services;
|
namespace Registration.API.Services;
|
||||||
|
|
||||||
public abstract class VbytesRelayServiceBase(
|
public abstract class VbytesRelayServiceBase(
|
||||||
IHttpClientFactory httpClientFactory,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options)
|
IOptions<VbytesRelayOptions> options)
|
||||||
{
|
{
|
||||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
private readonly HttpClient _httpClient = httpClient;
|
||||||
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)
|
||||||
{
|
{
|
||||||
var client = _httpClientFactory.CreateClient(VbytesParticipantRelayService.HttpClientName);
|
|
||||||
|
|
||||||
using var request = new HttpRequestMessage(HttpMethod.Post, BuildPath(path))
|
using var request = new HttpRequestMessage(HttpMethod.Post, BuildPath(path))
|
||||||
{
|
{
|
||||||
Content = JsonContent.Create(payload)
|
Content = JsonContent.Create(payload)
|
||||||
|
|
@ -22,13 +20,13 @@ public abstract class VbytesRelayServiceBase(
|
||||||
|
|
||||||
request.Headers.TryAddWithoutValidation(Options.ApiKeyHeaderName, Options.ApiKey);
|
request.Headers.TryAddWithoutValidation(Options.ApiKeyHeaderName, Options.ApiKey);
|
||||||
|
|
||||||
using var response = await client.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);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[DEBUG] Relay success body: {body}");
|
Console.WriteLine($"[DEBUG] Relay success body: {body}");
|
||||||
return new VbytesRelayResult(true, StatusCodes.Status200OK, "Request relayed successfully.");
|
return new VbytesRelayResult(true, StatusCodes.Status200OK, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
var statusCode = (int)response.StatusCode;
|
var statusCode = (int)response.StatusCode;
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ using Registration.Domain.Models;
|
||||||
namespace Registration.API.Services;
|
namespace Registration.API.Services;
|
||||||
|
|
||||||
public class VbytesVolunteerRelayService(
|
public class VbytesVolunteerRelayService(
|
||||||
IHttpClientFactory httpClientFactory,
|
HttpClient httpClient,
|
||||||
IOptions<VbytesRelayOptions> options,
|
IOptions<VbytesRelayOptions> options,
|
||||||
ILogger<VbytesVolunteerRelayService> logger)
|
ILogger<VbytesVolunteerRelayService> logger)
|
||||||
: VbytesRelayServiceBase(httpClientFactory, options), IVbytesVolunteerRelayService
|
: VbytesRelayServiceBase(httpClient, options), IVbytesVolunteerRelayService
|
||||||
{
|
{
|
||||||
private readonly ILogger<VbytesVolunteerRelayService> _logger = logger;
|
private readonly ILogger<VbytesVolunteerRelayService> _logger = logger;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ export default function RegisterPage() {
|
||||||
setMessage({ type: "info", text: "Processing your registration..." });
|
setMessage({ type: "info", text: "Processing your registration..." });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Check if the SSN has already been registered for the LAN
|
|
||||||
// Returns Ok (200) if NOT registered, Conflict (409) if registered
|
// Returns Ok (200) if NOT registered, Conflict (409) if registered
|
||||||
const checkRes = await fetch(`/api/Registration/registered/${formData.ssn}`);
|
const checkRes = await fetch(`/api/Registration/registered/${formData.ssn}`);
|
||||||
|
|
||||||
|
|
@ -56,17 +55,10 @@ export default function RegisterPage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Check membership status via GET Registration register
|
|
||||||
// Returns 200 (Ok) if member, 404 (NotFound) if not
|
// Returns 200 (Ok) if member, 404 (NotFound) if not
|
||||||
const validateRes = await fetch(`/api/Registration/register/${formData.ssn}`);
|
const validateRes = await fetch(`/api/Registration/register/${formData.ssn}`);
|
||||||
const isMember = validateRes.ok;
|
const isMember = validateRes.ok;
|
||||||
|
|
||||||
// 3. Register the SSN in the membership system via POST
|
|
||||||
await fetch(`/api/Registration/register/${formData.ssn}`, {
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. Register the participant for the event
|
|
||||||
const { ssn, ...participantData } = formData;
|
const { ssn, ...participantData } = formData;
|
||||||
const finalPayload = {
|
const finalPayload = {
|
||||||
...participantData,
|
...participantData,
|
||||||
|
|
@ -83,6 +75,10 @@ export default function RegisterPage() {
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setMessage({ type: "success", text: "Registration complete! You are now registered for the LAN." });
|
setMessage({ type: "success", text: "Registration complete! You are now registered for the LAN." });
|
||||||
|
|
||||||
|
await fetch(`/api/Registration/register/${formData.ssn}`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const errorData = await response.json();
|
const errorData = await response.json();
|
||||||
setMessage({ type: "error", text: errorData.message || "Event registration failed." });
|
setMessage({ type: "error", text: errorData.message || "Event registration failed." });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue